From ad187f7ac6b1ff41c869df4eacf3e289baaca3a1 Mon Sep 17 00:00:00 2001 From: mahamed eltorky <236695151+samarsamer251-glitch@users.noreply.github.com> Date: Fri, 27 Mar 2026 00:38:06 +0200 Subject: [PATCH 01/17] Clean up README.md by removing content Removed extensive documentation and examples from README.md. --- README. | 1 + README.md | 522 ------------------------------------------------------ 2 files changed, 1 insertion(+), 522 deletions(-) create mode 100644 README. delete mode 100644 README.md diff --git a/README. b/README. new file mode 100644 index 000000000..3314839bb --- /dev/null +++ b/README. @@ -0,0 +1 @@ +hgh diff --git a/README.md b/README.md deleted file mode 100644 index 15d6e9f53..000000000 --- a/README.md +++ /dev/null @@ -1,522 +0,0 @@ -# Metronome Python API library - - -[![PyPI version](https://img.shields.io/pypi/v/metronome-sdk.svg?label=pypi%20(stable))](https://pypi.org/project/metronome-sdk/) - -The Metronome Python library provides convenient access to the Metronome REST API from any Python 3.9+ -application. The library includes type definitions for all request params and response fields, -and offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx). - -## MCP Server - -Use the Metronome MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application. - -[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=%40metronome%2Fmcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBtZXRyb25vbWUvbWNwIl0sImVudiI6eyJNRVRST05PTUVfQkVBUkVSX1RPS0VOIjoiTXkgQmVhcmVyIFRva2VuIiwiTUVUUk9OT01FX1dFQkhPT0tfU0VDUkVUIjoiTXkgV2ViaG9vayBTZWNyZXQifX0) -[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40metronome%2Fmcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40metronome%2Fmcp%22%5D%2C%22env%22%3A%7B%22METRONOME_BEARER_TOKEN%22%3A%22My%20Bearer%20Token%22%2C%22METRONOME_WEBHOOK_SECRET%22%3A%22My%20Webhook%20Secret%22%7D%7D) - -> Note: You may need to set environment variables in your MCP client. - -## Documentation - -The REST API documentation can be found on [docs.metronome.com](https://docs.metronome.com). The full API of this library can be found in [api.md](api.md). - -## Installation - -```sh -# install from PyPI -pip install metronome-sdk -``` - -## Usage - -The full API of this library can be found in [api.md](api.md). - -```python -import os -from metronome import Metronome - -client = Metronome( - bearer_token=os.environ.get("METRONOME_BEARER_TOKEN"), # This is the default and can be omitted -) - -client.v1.usage.ingest( - usage=[ - { - "transaction_id": "90e9401f-0f8c-4cd3-9a9f-d6beb56d8d72", - "customer_id": "team@example.com", - "event_type": "heartbeat", - "timestamp": "2024-01-01T00:00:00Z", - "properties": { - "cluster_id": "42", - "cpu_seconds": 60, - "region": "Europe", - }, - } - ], -) -``` - -While you can provide a `bearer_token` keyword argument, -we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/) -to add `METRONOME_BEARER_TOKEN="My Bearer Token"` to your `.env` file -so that your Bearer Token is not stored in source control. - -## Async usage - -Simply import `AsyncMetronome` instead of `Metronome` and use `await` with each API call: - -```python -import os -import asyncio -from metronome import AsyncMetronome - -client = AsyncMetronome( - bearer_token=os.environ.get("METRONOME_BEARER_TOKEN"), # This is the default and can be omitted -) - - -async def main() -> None: - await client.v1.usage.ingest( - usage=[ - { - "transaction_id": "90e9401f-0f8c-4cd3-9a9f-d6beb56d8d72", - "customer_id": "team@example.com", - "event_type": "heartbeat", - "timestamp": "2024-01-01T00:00:00Z", - "properties": { - "cluster_id": "42", - "cpu_seconds": 60, - "region": "Europe", - }, - } - ], - ) - - -asyncio.run(main()) -``` - -Functionality between the synchronous and asynchronous clients is otherwise identical. - -### With aiohttp - -By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend. - -You can enable this by installing `aiohttp`: - -```sh -# install from PyPI -pip install metronome-sdk[aiohttp] -``` - -Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`: - -```python -import os -import asyncio -from metronome import DefaultAioHttpClient -from metronome import AsyncMetronome - - -async def main() -> None: - async with AsyncMetronome( - bearer_token=os.environ.get( - "METRONOME_BEARER_TOKEN" - ), # This is the default and can be omitted - http_client=DefaultAioHttpClient(), - ) as client: - await client.v1.usage.ingest( - usage=[ - { - "transaction_id": "90e9401f-0f8c-4cd3-9a9f-d6beb56d8d72", - "customer_id": "team@example.com", - "event_type": "heartbeat", - "timestamp": "2024-01-01T00:00:00Z", - "properties": { - "cluster_id": "42", - "cpu_seconds": 60, - "region": "Europe", - }, - } - ], - ) - - -asyncio.run(main()) -``` - -## Using types - -Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like: - -- Serializing back into JSON, `model.to_json()` -- Converting to a dictionary, `model.to_dict()` - -Typed requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`. - -## Pagination - -List methods in the Metronome API are paginated. - -This library provides auto-paginating iterators with each list response, so you do not have to request successive pages manually: - -```python -from metronome import Metronome - -client = Metronome() - -all_products = [] -# Automatically fetches more pages as needed. -for product in client.v1.contracts.products.list(): - # Do something with product here - all_products.append(product) -print(all_products) -``` - -Or, asynchronously: - -```python -import asyncio -from metronome import AsyncMetronome - -client = AsyncMetronome() - - -async def main() -> None: - all_products = [] - # Iterate through items across all pages, issuing requests as needed. - async for product in client.v1.contracts.products.list(): - all_products.append(product) - print(all_products) - - -asyncio.run(main()) -``` - -Alternatively, you can use the `.has_next_page()`, `.next_page_info()`, or `.get_next_page()` methods for more granular control working with pages: - -```python -first_page = await client.v1.contracts.products.list() -if first_page.has_next_page(): - print(f"will fetch next page using these details: {first_page.next_page_info()}") - next_page = await first_page.get_next_page() - print(f"number of items we just fetched: {len(next_page.data)}") - -# Remove `await` for non-async usage. -``` - -Or just work directly with the returned data: - -```python -first_page = await client.v1.contracts.products.list() - -print(f"next page cursor: {first_page.next_page}") # => "next page cursor: ..." -for product in first_page.data: - print(product.id) - -# Remove `await` for non-async usage. -``` - -from datetime import datetime - -## Nested params - -Nested parameters are dictionaries, typed using `TypedDict`, for example: - -```python -from metronome import Metronome - -client = Metronome() - -contract = client.v1.contracts.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=datetime.fromisoformat("2020-01-01T00:00:00.000"), - billing_provider_configuration={ - "billing_provider": "stripe", - "delivery_method": "direct_to_billing_provider", - }, -) -print(contract.billing_provider_configuration) -``` - -## Handling errors - -When the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `metronome.APIConnectionError` is raised. - -When the API returns a non-success status code (that is, 4xx or 5xx -response), a subclass of `metronome.APIStatusError` is raised, containing `status_code` and `response` properties. - -All errors inherit from `metronome.APIError`. - -```python -from datetime import datetime - -import metronome -from metronome import Metronome - -client = Metronome() - -try: - client.v1.contracts.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=datetime.fromisoformat("2020-01-01T00:00:00.000"), - ) -except metronome.APIConnectionError as e: - print("The server could not be reached") - print(e.__cause__) # an underlying Exception, likely raised within httpx. -except metronome.RateLimitError as e: - print("A 429 status code was received; we should back off a bit.") -except metronome.APIStatusError as e: - print("Another non-200-range status code was received") - print(e.status_code) - print(e.response) -``` - -Error codes are as follows: - -| Status Code | Error Type | -| ----------- | -------------------------- | -| 400 | `BadRequestError` | -| 401 | `AuthenticationError` | -| 403 | `PermissionDeniedError` | -| 404 | `NotFoundError` | -| 422 | `UnprocessableEntityError` | -| 429 | `RateLimitError` | -| >=500 | `InternalServerError` | -| N/A | `APIConnectionError` | - -### Retries - -Certain errors are automatically retried 2 times by default, with a short exponential backoff. -Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, -429 Rate Limit, and >=500 Internal errors are all retried by default. - -You can use the `max_retries` option to configure or disable retry settings: - -```python -from datetime import datetime - -from metronome import Metronome - -# Configure the default for all requests: -client = Metronome( - # default is 2 - max_retries=0, -) - -# Or, configure per-request: -client.with_options(max_retries=5).v1.contracts.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=datetime.fromisoformat("2020-01-01T00:00:00.000"), -) -``` - -### Timeouts - -By default requests time out after 1 minute. You can configure this with a `timeout` option, -which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object: - -```python -from datetime import datetime - -from metronome import Metronome - -# Configure the default for all requests: -client = Metronome( - # 20 seconds (default is 1 minute) - timeout=20.0, -) - -# More granular control: -client = Metronome( - timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0), -) - -# Override per-request: -client.with_options(timeout=5.0).v1.contracts.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=datetime.fromisoformat("2020-01-01T00:00:00.000"), -) -``` - -On timeout, an `APITimeoutError` is thrown. - -Note that requests that time out are [retried twice by default](#retries). - -## Advanced - -### Logging - -We use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module. - -You can enable logging by setting the environment variable `METRONOME_LOG` to `info`. - -```shell -$ export METRONOME_LOG=info -``` - -Or to `debug` for more verbose logging. - -### How to tell whether `None` means `null` or missing - -In an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`: - -```py -if response.my_field is None: - if 'my_field' not in response.model_fields_set: - print('Got json like {}, without a "my_field" key present at all.') - else: - print('Got json like {"my_field": null}.') -``` - -### Accessing raw response data (e.g. headers) - -The "raw" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g., - -```py -from datetime import datetime - -from metronome import Metronome - -client = Metronome() -response = client.v1.contracts.with_raw_response.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=datetime.fromisoformat("2020-01-01T00:00:00.000"), -) -print(response.headers.get('X-My-Header')) - -contract = response.parse() # get the object that `v1.contracts.create()` would have returned -print(contract.data) -``` - -from datetime import datetime - -These methods return an [`APIResponse`](https://github.com/Metronome-Industries/metronome-python/tree/main/src/metronome/_response.py) object. - -The async client returns an [`AsyncAPIResponse`](https://github.com/Metronome-Industries/metronome-python/tree/main/src/metronome/_response.py) with the same structure, the only difference being `await`able methods for reading the response content. - -#### `.with_streaming_response` - -The above interface eagerly reads the full response body when you make the request, which may not always be what you want. - -To stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods. - -```python -with client.v1.contracts.with_streaming_response.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=datetime.fromisoformat("2020-01-01T00:00:00.000"), -) as response: - print(response.headers.get("X-My-Header")) - - for line in response.iter_lines(): - print(line) -``` - -The context manager is required so that the response will reliably be closed. - -### Making custom/undocumented requests - -This library is typed for convenient access to the documented API. - -If you need to access undocumented endpoints, params, or response properties, the library can still be used. - -#### Undocumented endpoints - -To make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other -http verbs. Options on the client will be respected (such as retries) when making this request. - -```py -import httpx - -response = client.post( - "/foo", - cast_to=httpx.Response, - body={"my_param": True}, -) - -print(response.headers.get("x-foo")) -``` - -#### Undocumented request params - -If you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` request -options. - -#### Undocumented response properties - -To access undocumented response properties, you can access the extra fields like `response.unknown_prop`. You -can also get all the extra fields on the Pydantic model as a dict with -[`response.model_extra`](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_extra). - -### Configuring the HTTP client - -You can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including: - -- Support for [proxies](https://www.python-httpx.org/advanced/proxies/) -- Custom [transports](https://www.python-httpx.org/advanced/transports/) -- Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality - -```python -import httpx -from metronome import Metronome, DefaultHttpxClient - -client = Metronome( - # Or use the `METRONOME_BASE_URL` env var - base_url="http://my.test.server.example.com:8083", - http_client=DefaultHttpxClient( - proxy="http://my.test.proxy.example.com", - transport=httpx.HTTPTransport(local_address="0.0.0.0"), - ), -) -``` - -You can also customize the client on a per-request basis by using `with_options()`: - -```python -client.with_options(http_client=DefaultHttpxClient(...)) -``` - -### Managing HTTP resources - -By default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting. - -```py -from metronome import Metronome - -with Metronome() as client: - # make requests here - ... - -# HTTP client is now closed -``` - -## Versioning - -This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: - -1. Changes that only affect static types, without breaking runtime behavior. -2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_ -3. Changes that we do not expect to impact the vast majority of users in practice. - -We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. - -We are keen for your feedback; please open an [issue](https://www.github.com/Metronome-Industries/metronome-python/issues) with questions, bugs, or suggestions. - -### Determining the installed version - -If you've upgraded to the latest version but aren't seeing any new features you were expecting then your python environment is likely still using an older version. - -You can determine the version that is being used at runtime with: - -```py -import metronome -print(metronome.__version__) -``` - -## Requirements - -Python 3.9 or higher. - -## Contributing - -See [the contributing documentation](./CONTRIBUTING.md). From 9e253ded3628f1c46de8fe60b3f390198a89bd51 Mon Sep 17 00:00:00 2001 From: mahamed eltorky <236695151+samarsamer251-glitch@users.noreply.github.com> Date: Fri, 27 Mar 2026 00:38:30 +0200 Subject: [PATCH 02/17] Delete README. --- README. | 1 - 1 file changed, 1 deletion(-) delete mode 100644 README. diff --git a/README. b/README. deleted file mode 100644 index 3314839bb..000000000 --- a/README. +++ /dev/null @@ -1 +0,0 @@ -hgh From 75184ee23e3ef5dc7bcb0fe877cde0297c467cc1 Mon Sep 17 00:00:00 2001 From: mahamed eltorky <236695151+samarsamer251-glitch@users.noreply.github.com> Date: Fri, 27 Mar 2026 00:39:02 +0200 Subject: [PATCH 03/17] Delete .python-version --- .python-version | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .python-version diff --git a/.python-version b/.python-version deleted file mode 100644 index 43077b246..000000000 --- a/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.9.18 From 1112329c82d8a0192b04e51bebabe98c1e710009 Mon Sep 17 00:00:00 2001 From: mahamed eltorky <236695151+samarsamer251-glitch@users.noreply.github.com> Date: Fri, 27 Mar 2026 00:39:16 +0200 Subject: [PATCH 04/17] Delete .vscode directory --- .vscode/settings.json | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 5b0103078..000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "python.analysis.importFormat": "relative", -} From c8419c4e49b1fbed681e9e6e5eeadea832598102 Mon Sep 17 00:00:00 2001 From: mahamed eltorky <236695151+samarsamer251-glitch@users.noreply.github.com> Date: Fri, 27 Mar 2026 00:39:31 +0200 Subject: [PATCH 05/17] Delete bin directory --- bin/check-release-environment | 21 --------------------- bin/publish-pypi | 6 ------ 2 files changed, 27 deletions(-) delete mode 100644 bin/check-release-environment delete mode 100644 bin/publish-pypi diff --git a/bin/check-release-environment b/bin/check-release-environment deleted file mode 100644 index b845b0f4c..000000000 --- a/bin/check-release-environment +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash - -errors=() - -if [ -z "${PYPI_TOKEN}" ]; then - errors+=("The PYPI_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets.") -fi - -lenErrors=${#errors[@]} - -if [[ lenErrors -gt 0 ]]; then - echo -e "Found the following errors in the release environment:\n" - - for error in "${errors[@]}"; do - echo -e "- $error\n" - done - - exit 1 -fi - -echo "The environment is ready to push releases!" diff --git a/bin/publish-pypi b/bin/publish-pypi deleted file mode 100644 index 826054e92..000000000 --- a/bin/publish-pypi +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash - -set -eux -mkdir -p dist -rye build --clean -rye publish --yes --token=$PYPI_TOKEN From 372f3d6dc4853b9a68f415102c2b606cdd4db2ff Mon Sep 17 00:00:00 2001 From: mahamed eltorky <236695151+samarsamer251-glitch@users.noreply.github.com> Date: Fri, 27 Mar 2026 00:39:45 +0200 Subject: [PATCH 06/17] Delete scripts directory --- scripts/bootstrap | 27 ----- scripts/format | 8 -- scripts/lint | 16 --- scripts/mock | 52 ---------- scripts/test | 61 ----------- scripts/utils/ruffen-docs.py | 167 ------------------------------- scripts/utils/upload-artifact.sh | 27 ----- 7 files changed, 358 deletions(-) delete mode 100755 scripts/bootstrap delete mode 100755 scripts/format delete mode 100755 scripts/lint delete mode 100755 scripts/mock delete mode 100755 scripts/test delete mode 100644 scripts/utils/ruffen-docs.py delete mode 100755 scripts/utils/upload-artifact.sh diff --git a/scripts/bootstrap b/scripts/bootstrap deleted file mode 100755 index b430fee36..000000000 --- a/scripts/bootstrap +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash - -set -e - -cd "$(dirname "$0")/.." - -if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ] && [ -t 0 ]; then - brew bundle check >/dev/null 2>&1 || { - echo -n "==> Install Homebrew dependencies? (y/N): " - read -r response - case "$response" in - [yY][eE][sS]|[yY]) - brew bundle - ;; - *) - ;; - esac - echo - } -fi - -echo "==> Installing Python dependencies…" - -# experimental uv support makes installations significantly faster -rye config --set-bool behavior.use-uv=true - -rye sync --all-features diff --git a/scripts/format b/scripts/format deleted file mode 100755 index 667ec2d7a..000000000 --- a/scripts/format +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash - -set -e - -cd "$(dirname "$0")/.." - -echo "==> Running formatters" -rye run format diff --git a/scripts/lint b/scripts/lint deleted file mode 100755 index 14179023e..000000000 --- a/scripts/lint +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash - -set -e - -cd "$(dirname "$0")/.." - -if [ "$1" = "--fix" ]; then - echo "==> Running lints with --fix" - rye run fix:ruff -else - echo "==> Running lints" - rye run lint -fi - -echo "==> Making sure it imports" -rye run python -c 'import metronome' diff --git a/scripts/mock b/scripts/mock deleted file mode 100755 index bcf3b392b..000000000 --- a/scripts/mock +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env bash - -set -e - -cd "$(dirname "$0")/.." - -if [[ -n "$1" && "$1" != '--'* ]]; then - URL="$1" - shift -else - URL="$(grep 'openapi_spec_url' .stats.yml | cut -d' ' -f2)" -fi - -# Check if the URL is empty -if [ -z "$URL" ]; then - echo "Error: No OpenAPI spec path/url provided or found in .stats.yml" - exit 1 -fi - -echo "==> Starting mock server with URL ${URL}" - -# Run prism mock on the given spec -if [ "$1" == "--daemon" ]; then - # Pre-install the package so the download doesn't eat into the startup timeout - npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism --version - - npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log & - - # Wait for server to come online (max 30s) - echo -n "Waiting for server" - attempts=0 - while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do - attempts=$((attempts + 1)) - if [ "$attempts" -ge 300 ]; then - echo - echo "Timed out waiting for Prism server to start" - cat .prism.log - exit 1 - fi - echo -n "." - sleep 0.1 - done - - if grep -q "✖ fatal" ".prism.log"; then - cat .prism.log - exit 1 - fi - - echo -else - npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" -fi diff --git a/scripts/test b/scripts/test deleted file mode 100755 index dbeda2d21..000000000 --- a/scripts/test +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env bash - -set -e - -cd "$(dirname "$0")/.." - -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[0;33m' -NC='\033[0m' # No Color - -function prism_is_running() { - curl --silent "http://localhost:4010" >/dev/null 2>&1 -} - -kill_server_on_port() { - pids=$(lsof -t -i tcp:"$1" || echo "") - if [ "$pids" != "" ]; then - kill "$pids" - echo "Stopped $pids." - fi -} - -function is_overriding_api_base_url() { - [ -n "$TEST_API_BASE_URL" ] -} - -if ! is_overriding_api_base_url && ! prism_is_running ; then - # When we exit this script, make sure to kill the background mock server process - trap 'kill_server_on_port 4010' EXIT - - # Start the dev server - ./scripts/mock --daemon -fi - -if is_overriding_api_base_url ; then - echo -e "${GREEN}✔ Running tests against ${TEST_API_BASE_URL}${NC}" - echo -elif ! prism_is_running ; then - echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Prism server" - echo -e "running against your OpenAPI spec." - echo - echo -e "To run the server, pass in the path or url of your OpenAPI" - echo -e "spec to the prism command:" - echo - echo -e " \$ ${YELLOW}npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock path/to/your.openapi.yml${NC}" - echo - - exit 1 -else - echo -e "${GREEN}✔ Mock prism server is running with your OpenAPI spec${NC}" - echo -fi - -export DEFER_PYDANTIC_BUILD=false - -echo "==> Running tests" -rye run pytest "$@" - -echo "==> Running Pydantic v1 tests" -rye run nox -s test-pydantic-v1 -- "$@" diff --git a/scripts/utils/ruffen-docs.py b/scripts/utils/ruffen-docs.py deleted file mode 100644 index 0cf2bd2fd..000000000 --- a/scripts/utils/ruffen-docs.py +++ /dev/null @@ -1,167 +0,0 @@ -# fork of https://github.com/asottile/blacken-docs adapted for ruff -from __future__ import annotations - -import re -import sys -import argparse -import textwrap -import contextlib -import subprocess -from typing import Match, Optional, Sequence, Generator, NamedTuple, cast - -MD_RE = re.compile( - r"(?P^(?P *)```\s*python\n)" r"(?P.*?)" r"(?P^(?P=indent)```\s*$)", - re.DOTALL | re.MULTILINE, -) -MD_PYCON_RE = re.compile( - r"(?P^(?P *)```\s*pycon\n)" r"(?P.*?)" r"(?P^(?P=indent)```.*$)", - re.DOTALL | re.MULTILINE, -) -PYCON_PREFIX = ">>> " -PYCON_CONTINUATION_PREFIX = "..." -PYCON_CONTINUATION_RE = re.compile( - rf"^{re.escape(PYCON_CONTINUATION_PREFIX)}( |$)", -) -DEFAULT_LINE_LENGTH = 100 - - -class CodeBlockError(NamedTuple): - offset: int - exc: Exception - - -def format_str( - src: str, -) -> tuple[str, Sequence[CodeBlockError]]: - errors: list[CodeBlockError] = [] - - @contextlib.contextmanager - def _collect_error(match: Match[str]) -> Generator[None, None, None]: - try: - yield - except Exception as e: - errors.append(CodeBlockError(match.start(), e)) - - def _md_match(match: Match[str]) -> str: - code = textwrap.dedent(match["code"]) - with _collect_error(match): - code = format_code_block(code) - code = textwrap.indent(code, match["indent"]) - return f"{match['before']}{code}{match['after']}" - - def _pycon_match(match: Match[str]) -> str: - code = "" - fragment = cast(Optional[str], None) - - def finish_fragment() -> None: - nonlocal code - nonlocal fragment - - if fragment is not None: - with _collect_error(match): - fragment = format_code_block(fragment) - fragment_lines = fragment.splitlines() - code += f"{PYCON_PREFIX}{fragment_lines[0]}\n" - for line in fragment_lines[1:]: - # Skip blank lines to handle Black adding a blank above - # functions within blocks. A blank line would end the REPL - # continuation prompt. - # - # >>> if True: - # ... def f(): - # ... pass - # ... - if line: - code += f"{PYCON_CONTINUATION_PREFIX} {line}\n" - if fragment_lines[-1].startswith(" "): - code += f"{PYCON_CONTINUATION_PREFIX}\n" - fragment = None - - indentation = None - for line in match["code"].splitlines(): - orig_line, line = line, line.lstrip() - if indentation is None and line: - indentation = len(orig_line) - len(line) - continuation_match = PYCON_CONTINUATION_RE.match(line) - if continuation_match and fragment is not None: - fragment += line[continuation_match.end() :] + "\n" - else: - finish_fragment() - if line.startswith(PYCON_PREFIX): - fragment = line[len(PYCON_PREFIX) :] + "\n" - else: - code += orig_line[indentation:] + "\n" - finish_fragment() - return code - - def _md_pycon_match(match: Match[str]) -> str: - code = _pycon_match(match) - code = textwrap.indent(code, match["indent"]) - return f"{match['before']}{code}{match['after']}" - - src = MD_RE.sub(_md_match, src) - src = MD_PYCON_RE.sub(_md_pycon_match, src) - return src, errors - - -def format_code_block(code: str) -> str: - return subprocess.check_output( - [ - sys.executable, - "-m", - "ruff", - "format", - "--stdin-filename=script.py", - f"--line-length={DEFAULT_LINE_LENGTH}", - ], - encoding="utf-8", - input=code, - ) - - -def format_file( - filename: str, - skip_errors: bool, -) -> int: - with open(filename, encoding="UTF-8") as f: - contents = f.read() - new_contents, errors = format_str(contents) - for error in errors: - lineno = contents[: error.offset].count("\n") + 1 - print(f"{filename}:{lineno}: code block parse error {error.exc}") - if errors and not skip_errors: - return 1 - if contents != new_contents: - print(f"{filename}: Rewriting...") - with open(filename, "w", encoding="UTF-8") as f: - f.write(new_contents) - return 0 - else: - return 0 - - -def main(argv: Sequence[str] | None = None) -> int: - parser = argparse.ArgumentParser() - parser.add_argument( - "-l", - "--line-length", - type=int, - default=DEFAULT_LINE_LENGTH, - ) - parser.add_argument( - "-S", - "--skip-string-normalization", - action="store_true", - ) - parser.add_argument("-E", "--skip-errors", action="store_true") - parser.add_argument("filenames", nargs="*") - args = parser.parse_args(argv) - - retv = 0 - for filename in args.filenames: - retv |= format_file(filename, skip_errors=args.skip_errors) - return retv - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh deleted file mode 100755 index d68c0fa32..000000000 --- a/scripts/utils/upload-artifact.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash -set -exuo pipefail - -FILENAME=$(basename dist/*.whl) - -RESPONSE=$(curl -X POST "$URL?filename=$FILENAME" \ - -H "Authorization: Bearer $AUTH" \ - -H "Content-Type: application/json") - -SIGNED_URL=$(echo "$RESPONSE" | jq -r '.url') - -if [[ "$SIGNED_URL" == "null" ]]; then - echo -e "\033[31mFailed to get signed URL.\033[0m" - exit 1 -fi - -UPLOAD_RESPONSE=$(curl -v -X PUT \ - -H "Content-Type: binary/octet-stream" \ - --data-binary "@dist/$FILENAME" "$SIGNED_URL" 2>&1) - -if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then - echo -e "\033[32mUploaded build to Stainless storage.\033[0m" - echo -e "\033[32mInstallation: pip install 'https://pkg.stainless.com/s/metronome-python/$SHA/$FILENAME'\033[0m" -else - echo -e "\033[31mFailed to upload artifact.\033[0m" - exit 1 -fi From a16db3be7b5c7535ef9d0dfc705a29ca7cd11add Mon Sep 17 00:00:00 2001 From: mahamed eltorky <236695151+samarsamer251-glitch@users.noreply.github.com> Date: Fri, 27 Mar 2026 00:40:02 +0200 Subject: [PATCH 07/17] Delete tests directory --- tests/__init__.py | 1 - tests/api_resources/__init__.py | 1 - tests/api_resources/v1/__init__.py | 1 - tests/api_resources/v1/contracts/__init__.py | 1 - .../v1/contracts/rate_cards/__init__.py | 1 - .../rate_cards/test_named_schedules.py | 231 -- .../rate_cards/test_product_orders.py | 217 -- .../v1/contracts/rate_cards/test_rates.py | 444 --- .../v1/contracts/test_named_schedules.py | 215 -- .../v1/contracts/test_products.py | 472 --- .../v1/contracts/test_rate_cards.py | 539 ---- tests/api_resources/v1/customers/__init__.py | 1 - .../api_resources/v1/customers/test_alerts.py | 282 -- .../v1/customers/test_billing_config.py | 312 -- .../v1/customers/test_commits.py | 468 --- .../v1/customers/test_credits.py | 402 --- .../v1/customers/test_invoices.py | 647 ---- .../v1/customers/test_named_schedules.py | 215 -- .../api_resources/v1/customers/test_plans.py | 521 --- tests/api_resources/v1/settings/__init__.py | 1 - .../v1/settings/test_billing_providers.py | 183 -- tests/api_resources/v1/test_alerts.py | 244 -- tests/api_resources/v1/test_audit_logs.py | 102 - .../api_resources/v1/test_billable_metrics.py | 370 --- tests/api_resources/v1/test_contracts.py | 2829 ----------------- tests/api_resources/v1/test_credit_grants.py | 553 ---- tests/api_resources/v1/test_custom_fields.py | 387 --- tests/api_resources/v1/test_customers.py | 1366 -------- tests/api_resources/v1/test_dashboards.py | 160 - tests/api_resources/v1/test_invoices.py | 151 - tests/api_resources/v1/test_packages.py | 1122 ------- tests/api_resources/v1/test_payments.py | 255 -- tests/api_resources/v1/test_plans.py | 362 --- tests/api_resources/v1/test_pricing_units.py | 91 - tests/api_resources/v1/test_services.py | 74 - tests/api_resources/v1/test_settings.py | 126 - tests/api_resources/v1/test_usage.py | 413 --- tests/api_resources/v2/__init__.py | 1 - tests/api_resources/v2/test_contracts.py | 2038 ------------ tests/conftest.py | 84 - tests/sample_file.txt | 1 - tests/test_client.py | 1996 ------------ tests/test_deepcopy.py | 58 - tests/test_extract_files.py | 64 - tests/test_files.py | 51 - tests/test_models.py | 963 ------ tests/test_qs.py | 78 - tests/test_required_args.py | 111 - tests/test_response.py | 277 -- tests/test_streaming.py | 248 -- tests/test_transform.py | 459 --- tests/test_utils/test_datetime_parse.py | 110 - tests/test_utils/test_json.py | 126 - tests/test_utils/test_proxy.py | 34 - tests/test_utils/test_typing.py | 73 - tests/utils.py | 167 - 56 files changed, 20699 deletions(-) delete mode 100644 tests/__init__.py delete mode 100644 tests/api_resources/__init__.py delete mode 100644 tests/api_resources/v1/__init__.py delete mode 100644 tests/api_resources/v1/contracts/__init__.py delete mode 100644 tests/api_resources/v1/contracts/rate_cards/__init__.py delete mode 100644 tests/api_resources/v1/contracts/rate_cards/test_named_schedules.py delete mode 100644 tests/api_resources/v1/contracts/rate_cards/test_product_orders.py delete mode 100644 tests/api_resources/v1/contracts/rate_cards/test_rates.py delete mode 100644 tests/api_resources/v1/contracts/test_named_schedules.py delete mode 100644 tests/api_resources/v1/contracts/test_products.py delete mode 100644 tests/api_resources/v1/contracts/test_rate_cards.py delete mode 100644 tests/api_resources/v1/customers/__init__.py delete mode 100644 tests/api_resources/v1/customers/test_alerts.py delete mode 100644 tests/api_resources/v1/customers/test_billing_config.py delete mode 100644 tests/api_resources/v1/customers/test_commits.py delete mode 100644 tests/api_resources/v1/customers/test_credits.py delete mode 100644 tests/api_resources/v1/customers/test_invoices.py delete mode 100644 tests/api_resources/v1/customers/test_named_schedules.py delete mode 100644 tests/api_resources/v1/customers/test_plans.py delete mode 100644 tests/api_resources/v1/settings/__init__.py delete mode 100644 tests/api_resources/v1/settings/test_billing_providers.py delete mode 100644 tests/api_resources/v1/test_alerts.py delete mode 100644 tests/api_resources/v1/test_audit_logs.py delete mode 100644 tests/api_resources/v1/test_billable_metrics.py delete mode 100644 tests/api_resources/v1/test_contracts.py delete mode 100644 tests/api_resources/v1/test_credit_grants.py delete mode 100644 tests/api_resources/v1/test_custom_fields.py delete mode 100644 tests/api_resources/v1/test_customers.py delete mode 100644 tests/api_resources/v1/test_dashboards.py delete mode 100644 tests/api_resources/v1/test_invoices.py delete mode 100644 tests/api_resources/v1/test_packages.py delete mode 100644 tests/api_resources/v1/test_payments.py delete mode 100644 tests/api_resources/v1/test_plans.py delete mode 100644 tests/api_resources/v1/test_pricing_units.py delete mode 100644 tests/api_resources/v1/test_services.py delete mode 100644 tests/api_resources/v1/test_settings.py delete mode 100644 tests/api_resources/v1/test_usage.py delete mode 100644 tests/api_resources/v2/__init__.py delete mode 100644 tests/api_resources/v2/test_contracts.py delete mode 100644 tests/conftest.py delete mode 100644 tests/sample_file.txt delete mode 100644 tests/test_client.py delete mode 100644 tests/test_deepcopy.py delete mode 100644 tests/test_extract_files.py delete mode 100644 tests/test_files.py delete mode 100644 tests/test_models.py delete mode 100644 tests/test_qs.py delete mode 100644 tests/test_required_args.py delete mode 100644 tests/test_response.py delete mode 100644 tests/test_streaming.py delete mode 100644 tests/test_transform.py delete mode 100644 tests/test_utils/test_datetime_parse.py delete mode 100644 tests/test_utils/test_json.py delete mode 100644 tests/test_utils/test_proxy.py delete mode 100644 tests/test_utils/test_typing.py delete mode 100644 tests/utils.py diff --git a/tests/__init__.py b/tests/__init__.py deleted file mode 100644 index fd8019a9a..000000000 --- a/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/__init__.py b/tests/api_resources/__init__.py deleted file mode 100644 index fd8019a9a..000000000 --- a/tests/api_resources/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/v1/__init__.py b/tests/api_resources/v1/__init__.py deleted file mode 100644 index fd8019a9a..000000000 --- a/tests/api_resources/v1/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/v1/contracts/__init__.py b/tests/api_resources/v1/contracts/__init__.py deleted file mode 100644 index fd8019a9a..000000000 --- a/tests/api_resources/v1/contracts/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/v1/contracts/rate_cards/__init__.py b/tests/api_resources/v1/contracts/rate_cards/__init__.py deleted file mode 100644 index fd8019a9a..000000000 --- a/tests/api_resources/v1/contracts/rate_cards/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/v1/contracts/rate_cards/test_named_schedules.py b/tests/api_resources/v1/contracts/rate_cards/test_named_schedules.py deleted file mode 100644 index 85c5c7c63..000000000 --- a/tests/api_resources/v1/contracts/rate_cards/test_named_schedules.py +++ /dev/null @@ -1,231 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome._utils import parse_datetime -from metronome.types.v1.contracts.rate_cards import ( - NamedScheduleRetrieveResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestNamedSchedules: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_retrieve(self, client: Metronome) -> None: - named_schedule = client.v1.contracts.rate_cards.named_schedules.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - ) - assert_matches_type(NamedScheduleRetrieveResponse, named_schedule, path=["response"]) - - @parametrize - def test_method_retrieve_with_all_params(self, client: Metronome) -> None: - named_schedule = client.v1.contracts.rate_cards.named_schedules.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - covering_date=parse_datetime("2022-02-15T00:00:00Z"), - ) - assert_matches_type(NamedScheduleRetrieveResponse, named_schedule, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Metronome) -> None: - response = client.v1.contracts.rate_cards.named_schedules.with_raw_response.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - named_schedule = response.parse() - assert_matches_type(NamedScheduleRetrieveResponse, named_schedule, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Metronome) -> None: - with client.v1.contracts.rate_cards.named_schedules.with_streaming_response.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - named_schedule = response.parse() - assert_matches_type(NamedScheduleRetrieveResponse, named_schedule, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_update(self, client: Metronome) -> None: - named_schedule = client.v1.contracts.rate_cards.named_schedules.update( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - starting_at=parse_datetime("2022-02-01T00:00:00Z"), - value={"my_key": "my_value"}, - ) - assert named_schedule is None - - @parametrize - def test_method_update_with_all_params(self, client: Metronome) -> None: - named_schedule = client.v1.contracts.rate_cards.named_schedules.update( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - starting_at=parse_datetime("2022-02-01T00:00:00Z"), - value={"my_key": "my_value"}, - ending_before=parse_datetime("2022-02-15T00:00:00Z"), - ) - assert named_schedule is None - - @parametrize - def test_raw_response_update(self, client: Metronome) -> None: - response = client.v1.contracts.rate_cards.named_schedules.with_raw_response.update( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - starting_at=parse_datetime("2022-02-01T00:00:00Z"), - value={"my_key": "my_value"}, - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - named_schedule = response.parse() - assert named_schedule is None - - @parametrize - def test_streaming_response_update(self, client: Metronome) -> None: - with client.v1.contracts.rate_cards.named_schedules.with_streaming_response.update( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - starting_at=parse_datetime("2022-02-01T00:00:00Z"), - value={"my_key": "my_value"}, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - named_schedule = response.parse() - assert named_schedule is None - - assert cast(Any, response.is_closed) is True - - -class TestAsyncNamedSchedules: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_retrieve(self, async_client: AsyncMetronome) -> None: - named_schedule = await async_client.v1.contracts.rate_cards.named_schedules.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - ) - assert_matches_type(NamedScheduleRetrieveResponse, named_schedule, path=["response"]) - - @parametrize - async def test_method_retrieve_with_all_params(self, async_client: AsyncMetronome) -> None: - named_schedule = await async_client.v1.contracts.rate_cards.named_schedules.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - covering_date=parse_datetime("2022-02-15T00:00:00Z"), - ) - assert_matches_type(NamedScheduleRetrieveResponse, named_schedule, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.rate_cards.named_schedules.with_raw_response.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - named_schedule = await response.parse() - assert_matches_type(NamedScheduleRetrieveResponse, named_schedule, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.rate_cards.named_schedules.with_streaming_response.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - named_schedule = await response.parse() - assert_matches_type(NamedScheduleRetrieveResponse, named_schedule, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_update(self, async_client: AsyncMetronome) -> None: - named_schedule = await async_client.v1.contracts.rate_cards.named_schedules.update( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - starting_at=parse_datetime("2022-02-01T00:00:00Z"), - value={"my_key": "my_value"}, - ) - assert named_schedule is None - - @parametrize - async def test_method_update_with_all_params(self, async_client: AsyncMetronome) -> None: - named_schedule = await async_client.v1.contracts.rate_cards.named_schedules.update( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - starting_at=parse_datetime("2022-02-01T00:00:00Z"), - value={"my_key": "my_value"}, - ending_before=parse_datetime("2022-02-15T00:00:00Z"), - ) - assert named_schedule is None - - @parametrize - async def test_raw_response_update(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.rate_cards.named_schedules.with_raw_response.update( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - starting_at=parse_datetime("2022-02-01T00:00:00Z"), - value={"my_key": "my_value"}, - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - named_schedule = await response.parse() - assert named_schedule is None - - @parametrize - async def test_streaming_response_update(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.rate_cards.named_schedules.with_streaming_response.update( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - starting_at=parse_datetime("2022-02-01T00:00:00Z"), - value={"my_key": "my_value"}, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - named_schedule = await response.parse() - assert named_schedule is None - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v1/contracts/rate_cards/test_product_orders.py b/tests/api_resources/v1/contracts/rate_cards/test_product_orders.py deleted file mode 100644 index 7a9c656f0..000000000 --- a/tests/api_resources/v1/contracts/rate_cards/test_product_orders.py +++ /dev/null @@ -1,217 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome.types.v1.contracts.rate_cards import ( - ProductOrderSetResponse, - ProductOrderUpdateResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestProductOrders: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_update(self, client: Metronome) -> None: - product_order = client.v1.contracts.rate_cards.product_orders.update( - product_moves=[ - { - "position": 0, - "product_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", - }, - { - "position": 1, - "product_id": "b086f2f4-9851-4466-9ca0-30d53e6a42ac", - }, - ], - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(ProductOrderUpdateResponse, product_order, path=["response"]) - - @parametrize - def test_raw_response_update(self, client: Metronome) -> None: - response = client.v1.contracts.rate_cards.product_orders.with_raw_response.update( - product_moves=[ - { - "position": 0, - "product_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", - }, - { - "position": 1, - "product_id": "b086f2f4-9851-4466-9ca0-30d53e6a42ac", - }, - ], - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - product_order = response.parse() - assert_matches_type(ProductOrderUpdateResponse, product_order, path=["response"]) - - @parametrize - def test_streaming_response_update(self, client: Metronome) -> None: - with client.v1.contracts.rate_cards.product_orders.with_streaming_response.update( - product_moves=[ - { - "position": 0, - "product_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", - }, - { - "position": 1, - "product_id": "b086f2f4-9851-4466-9ca0-30d53e6a42ac", - }, - ], - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - product_order = response.parse() - assert_matches_type(ProductOrderUpdateResponse, product_order, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_set(self, client: Metronome) -> None: - product_order = client.v1.contracts.rate_cards.product_orders.set( - product_order=["13117714-3f05-48e5-a6e9-a66093f13b4d", "b086f2f4-9851-4466-9ca0-30d53e6a42ac"], - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(ProductOrderSetResponse, product_order, path=["response"]) - - @parametrize - def test_raw_response_set(self, client: Metronome) -> None: - response = client.v1.contracts.rate_cards.product_orders.with_raw_response.set( - product_order=["13117714-3f05-48e5-a6e9-a66093f13b4d", "b086f2f4-9851-4466-9ca0-30d53e6a42ac"], - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - product_order = response.parse() - assert_matches_type(ProductOrderSetResponse, product_order, path=["response"]) - - @parametrize - def test_streaming_response_set(self, client: Metronome) -> None: - with client.v1.contracts.rate_cards.product_orders.with_streaming_response.set( - product_order=["13117714-3f05-48e5-a6e9-a66093f13b4d", "b086f2f4-9851-4466-9ca0-30d53e6a42ac"], - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - product_order = response.parse() - assert_matches_type(ProductOrderSetResponse, product_order, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncProductOrders: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_update(self, async_client: AsyncMetronome) -> None: - product_order = await async_client.v1.contracts.rate_cards.product_orders.update( - product_moves=[ - { - "position": 0, - "product_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", - }, - { - "position": 1, - "product_id": "b086f2f4-9851-4466-9ca0-30d53e6a42ac", - }, - ], - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(ProductOrderUpdateResponse, product_order, path=["response"]) - - @parametrize - async def test_raw_response_update(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.rate_cards.product_orders.with_raw_response.update( - product_moves=[ - { - "position": 0, - "product_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", - }, - { - "position": 1, - "product_id": "b086f2f4-9851-4466-9ca0-30d53e6a42ac", - }, - ], - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - product_order = await response.parse() - assert_matches_type(ProductOrderUpdateResponse, product_order, path=["response"]) - - @parametrize - async def test_streaming_response_update(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.rate_cards.product_orders.with_streaming_response.update( - product_moves=[ - { - "position": 0, - "product_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", - }, - { - "position": 1, - "product_id": "b086f2f4-9851-4466-9ca0-30d53e6a42ac", - }, - ], - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - product_order = await response.parse() - assert_matches_type(ProductOrderUpdateResponse, product_order, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_set(self, async_client: AsyncMetronome) -> None: - product_order = await async_client.v1.contracts.rate_cards.product_orders.set( - product_order=["13117714-3f05-48e5-a6e9-a66093f13b4d", "b086f2f4-9851-4466-9ca0-30d53e6a42ac"], - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(ProductOrderSetResponse, product_order, path=["response"]) - - @parametrize - async def test_raw_response_set(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.rate_cards.product_orders.with_raw_response.set( - product_order=["13117714-3f05-48e5-a6e9-a66093f13b4d", "b086f2f4-9851-4466-9ca0-30d53e6a42ac"], - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - product_order = await response.parse() - assert_matches_type(ProductOrderSetResponse, product_order, path=["response"]) - - @parametrize - async def test_streaming_response_set(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.rate_cards.product_orders.with_streaming_response.set( - product_order=["13117714-3f05-48e5-a6e9-a66093f13b4d", "b086f2f4-9851-4466-9ca0-30d53e6a42ac"], - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - product_order = await response.parse() - assert_matches_type(ProductOrderSetResponse, product_order, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v1/contracts/rate_cards/test_rates.py b/tests/api_resources/v1/contracts/rate_cards/test_rates.py deleted file mode 100644 index 1fb8f6589..000000000 --- a/tests/api_resources/v1/contracts/rate_cards/test_rates.py +++ /dev/null @@ -1,444 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome._utils import parse_datetime -from metronome.pagination import SyncCursorPage, AsyncCursorPage -from metronome.types.v1.contracts.rate_cards import ( - RateAddResponse, - RateListResponse, - RateAddManyResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestRates: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_list(self, client: Metronome) -> None: - rate = client.v1.contracts.rate_cards.rates.list( - at=parse_datetime("2024-01-01T00:00:00.000Z"), - rate_card_id="f3d51ae8-f283-44e1-9933-a3cf9ad7a6fe", - ) - assert_matches_type(SyncCursorPage[RateListResponse], rate, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Metronome) -> None: - rate = client.v1.contracts.rate_cards.rates.list( - at=parse_datetime("2024-01-01T00:00:00.000Z"), - rate_card_id="f3d51ae8-f283-44e1-9933-a3cf9ad7a6fe", - limit=1, - next_page="next_page", - selectors=[ - { - "billing_frequency": "MONTHLY", - "partial_pricing_group_values": { - "region": "us-west-2", - "cloud": "aws", - }, - "pricing_group_values": {"foo": "string"}, - "product_id": "d6300dbb-882e-4d2d-8dec-5125d16b65d0", - "product_tags": ["string"], - } - ], - ) - assert_matches_type(SyncCursorPage[RateListResponse], rate, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Metronome) -> None: - response = client.v1.contracts.rate_cards.rates.with_raw_response.list( - at=parse_datetime("2024-01-01T00:00:00.000Z"), - rate_card_id="f3d51ae8-f283-44e1-9933-a3cf9ad7a6fe", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - rate = response.parse() - assert_matches_type(SyncCursorPage[RateListResponse], rate, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Metronome) -> None: - with client.v1.contracts.rate_cards.rates.with_streaming_response.list( - at=parse_datetime("2024-01-01T00:00:00.000Z"), - rate_card_id="f3d51ae8-f283-44e1-9933-a3cf9ad7a6fe", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - rate = response.parse() - assert_matches_type(SyncCursorPage[RateListResponse], rate, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_add(self, client: Metronome) -> None: - rate = client.v1.contracts.rate_cards.rates.add( - entitled=True, - product_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - rate_type="FLAT", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) - assert_matches_type(RateAddResponse, rate, path=["response"]) - - @parametrize - def test_method_add_with_all_params(self, client: Metronome) -> None: - rate = client.v1.contracts.rate_cards.rates.add( - entitled=True, - product_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - rate_type="FLAT", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - billing_frequency="MONTHLY", - commit_rate={ - "rate_type": "FLAT", - "price": 0, - "tiers": [ - { - "price": 0, - "size": 0, - } - ], - }, - credit_type_id="2714e483-4ff1-48e4-9e25-ac732e8f24f2", - custom_rate={"foo": "bar"}, - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - is_prorated=True, - price=100, - pricing_group_values={"foo": "string"}, - quantity=0, - tiers=[ - { - "price": 0, - "size": 0, - } - ], - ) - assert_matches_type(RateAddResponse, rate, path=["response"]) - - @parametrize - def test_raw_response_add(self, client: Metronome) -> None: - response = client.v1.contracts.rate_cards.rates.with_raw_response.add( - entitled=True, - product_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - rate_type="FLAT", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - rate = response.parse() - assert_matches_type(RateAddResponse, rate, path=["response"]) - - @parametrize - def test_streaming_response_add(self, client: Metronome) -> None: - with client.v1.contracts.rate_cards.rates.with_streaming_response.add( - entitled=True, - product_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - rate_type="FLAT", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - rate = response.parse() - assert_matches_type(RateAddResponse, rate, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_add_many(self, client: Metronome) -> None: - rate = client.v1.contracts.rate_cards.rates.add_many( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - rates=[ - { - "entitled": True, - "product_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", - "rate_type": "FLAT", - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - }, - { - "entitled": True, - "product_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", - "rate_type": "FLAT", - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - }, - ], - ) - assert_matches_type(RateAddManyResponse, rate, path=["response"]) - - @parametrize - def test_raw_response_add_many(self, client: Metronome) -> None: - response = client.v1.contracts.rate_cards.rates.with_raw_response.add_many( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - rates=[ - { - "entitled": True, - "product_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", - "rate_type": "FLAT", - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - }, - { - "entitled": True, - "product_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", - "rate_type": "FLAT", - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - }, - ], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - rate = response.parse() - assert_matches_type(RateAddManyResponse, rate, path=["response"]) - - @parametrize - def test_streaming_response_add_many(self, client: Metronome) -> None: - with client.v1.contracts.rate_cards.rates.with_streaming_response.add_many( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - rates=[ - { - "entitled": True, - "product_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", - "rate_type": "FLAT", - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - }, - { - "entitled": True, - "product_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", - "rate_type": "FLAT", - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - }, - ], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - rate = response.parse() - assert_matches_type(RateAddManyResponse, rate, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncRates: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_list(self, async_client: AsyncMetronome) -> None: - rate = await async_client.v1.contracts.rate_cards.rates.list( - at=parse_datetime("2024-01-01T00:00:00.000Z"), - rate_card_id="f3d51ae8-f283-44e1-9933-a3cf9ad7a6fe", - ) - assert_matches_type(AsyncCursorPage[RateListResponse], rate, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncMetronome) -> None: - rate = await async_client.v1.contracts.rate_cards.rates.list( - at=parse_datetime("2024-01-01T00:00:00.000Z"), - rate_card_id="f3d51ae8-f283-44e1-9933-a3cf9ad7a6fe", - limit=1, - next_page="next_page", - selectors=[ - { - "billing_frequency": "MONTHLY", - "partial_pricing_group_values": { - "region": "us-west-2", - "cloud": "aws", - }, - "pricing_group_values": {"foo": "string"}, - "product_id": "d6300dbb-882e-4d2d-8dec-5125d16b65d0", - "product_tags": ["string"], - } - ], - ) - assert_matches_type(AsyncCursorPage[RateListResponse], rate, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.rate_cards.rates.with_raw_response.list( - at=parse_datetime("2024-01-01T00:00:00.000Z"), - rate_card_id="f3d51ae8-f283-44e1-9933-a3cf9ad7a6fe", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - rate = await response.parse() - assert_matches_type(AsyncCursorPage[RateListResponse], rate, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.rate_cards.rates.with_streaming_response.list( - at=parse_datetime("2024-01-01T00:00:00.000Z"), - rate_card_id="f3d51ae8-f283-44e1-9933-a3cf9ad7a6fe", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - rate = await response.parse() - assert_matches_type(AsyncCursorPage[RateListResponse], rate, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_add(self, async_client: AsyncMetronome) -> None: - rate = await async_client.v1.contracts.rate_cards.rates.add( - entitled=True, - product_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - rate_type="FLAT", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) - assert_matches_type(RateAddResponse, rate, path=["response"]) - - @parametrize - async def test_method_add_with_all_params(self, async_client: AsyncMetronome) -> None: - rate = await async_client.v1.contracts.rate_cards.rates.add( - entitled=True, - product_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - rate_type="FLAT", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - billing_frequency="MONTHLY", - commit_rate={ - "rate_type": "FLAT", - "price": 0, - "tiers": [ - { - "price": 0, - "size": 0, - } - ], - }, - credit_type_id="2714e483-4ff1-48e4-9e25-ac732e8f24f2", - custom_rate={"foo": "bar"}, - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - is_prorated=True, - price=100, - pricing_group_values={"foo": "string"}, - quantity=0, - tiers=[ - { - "price": 0, - "size": 0, - } - ], - ) - assert_matches_type(RateAddResponse, rate, path=["response"]) - - @parametrize - async def test_raw_response_add(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.rate_cards.rates.with_raw_response.add( - entitled=True, - product_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - rate_type="FLAT", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - rate = await response.parse() - assert_matches_type(RateAddResponse, rate, path=["response"]) - - @parametrize - async def test_streaming_response_add(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.rate_cards.rates.with_streaming_response.add( - entitled=True, - product_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - rate_type="FLAT", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - rate = await response.parse() - assert_matches_type(RateAddResponse, rate, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_add_many(self, async_client: AsyncMetronome) -> None: - rate = await async_client.v1.contracts.rate_cards.rates.add_many( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - rates=[ - { - "entitled": True, - "product_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", - "rate_type": "FLAT", - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - }, - { - "entitled": True, - "product_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", - "rate_type": "FLAT", - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - }, - ], - ) - assert_matches_type(RateAddManyResponse, rate, path=["response"]) - - @parametrize - async def test_raw_response_add_many(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.rate_cards.rates.with_raw_response.add_many( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - rates=[ - { - "entitled": True, - "product_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", - "rate_type": "FLAT", - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - }, - { - "entitled": True, - "product_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", - "rate_type": "FLAT", - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - }, - ], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - rate = await response.parse() - assert_matches_type(RateAddManyResponse, rate, path=["response"]) - - @parametrize - async def test_streaming_response_add_many(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.rate_cards.rates.with_streaming_response.add_many( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - rates=[ - { - "entitled": True, - "product_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", - "rate_type": "FLAT", - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - }, - { - "entitled": True, - "product_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", - "rate_type": "FLAT", - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - }, - ], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - rate = await response.parse() - assert_matches_type(RateAddManyResponse, rate, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v1/contracts/test_named_schedules.py b/tests/api_resources/v1/contracts/test_named_schedules.py deleted file mode 100644 index 7959a8536..000000000 --- a/tests/api_resources/v1/contracts/test_named_schedules.py +++ /dev/null @@ -1,215 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome._utils import parse_datetime -from metronome.types.v1.contracts import ( - NamedScheduleRetrieveResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestNamedSchedules: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_retrieve(self, client: Metronome) -> None: - named_schedule = client.v1.contracts.named_schedules.retrieve( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - schedule_name="my-schedule", - ) - assert_matches_type(NamedScheduleRetrieveResponse, named_schedule, path=["response"]) - - @parametrize - def test_method_retrieve_with_all_params(self, client: Metronome) -> None: - named_schedule = client.v1.contracts.named_schedules.retrieve( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - schedule_name="my-schedule", - covering_date=parse_datetime("2022-02-15T00:00:00Z"), - ) - assert_matches_type(NamedScheduleRetrieveResponse, named_schedule, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Metronome) -> None: - response = client.v1.contracts.named_schedules.with_raw_response.retrieve( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - schedule_name="my-schedule", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - named_schedule = response.parse() - assert_matches_type(NamedScheduleRetrieveResponse, named_schedule, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Metronome) -> None: - with client.v1.contracts.named_schedules.with_streaming_response.retrieve( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - schedule_name="my-schedule", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - named_schedule = response.parse() - assert_matches_type(NamedScheduleRetrieveResponse, named_schedule, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_update(self, client: Metronome) -> None: - named_schedule = client.v1.contracts.named_schedules.update( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - schedule_name="my-schedule", - starting_at=parse_datetime("2022-02-01T00:00:00Z"), - value={"my_key": "my_value"}, - ) - assert named_schedule is None - - @parametrize - def test_method_update_with_all_params(self, client: Metronome) -> None: - named_schedule = client.v1.contracts.named_schedules.update( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - schedule_name="my-schedule", - starting_at=parse_datetime("2022-02-01T00:00:00Z"), - value={"my_key": "my_value"}, - ending_before=parse_datetime("2022-02-15T00:00:00Z"), - ) - assert named_schedule is None - - @parametrize - def test_raw_response_update(self, client: Metronome) -> None: - response = client.v1.contracts.named_schedules.with_raw_response.update( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - schedule_name="my-schedule", - starting_at=parse_datetime("2022-02-01T00:00:00Z"), - value={"my_key": "my_value"}, - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - named_schedule = response.parse() - assert named_schedule is None - - @parametrize - def test_streaming_response_update(self, client: Metronome) -> None: - with client.v1.contracts.named_schedules.with_streaming_response.update( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - schedule_name="my-schedule", - starting_at=parse_datetime("2022-02-01T00:00:00Z"), - value={"my_key": "my_value"}, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - named_schedule = response.parse() - assert named_schedule is None - - assert cast(Any, response.is_closed) is True - - -class TestAsyncNamedSchedules: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_retrieve(self, async_client: AsyncMetronome) -> None: - named_schedule = await async_client.v1.contracts.named_schedules.retrieve( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - schedule_name="my-schedule", - ) - assert_matches_type(NamedScheduleRetrieveResponse, named_schedule, path=["response"]) - - @parametrize - async def test_method_retrieve_with_all_params(self, async_client: AsyncMetronome) -> None: - named_schedule = await async_client.v1.contracts.named_schedules.retrieve( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - schedule_name="my-schedule", - covering_date=parse_datetime("2022-02-15T00:00:00Z"), - ) - assert_matches_type(NamedScheduleRetrieveResponse, named_schedule, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.named_schedules.with_raw_response.retrieve( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - schedule_name="my-schedule", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - named_schedule = await response.parse() - assert_matches_type(NamedScheduleRetrieveResponse, named_schedule, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.named_schedules.with_streaming_response.retrieve( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - schedule_name="my-schedule", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - named_schedule = await response.parse() - assert_matches_type(NamedScheduleRetrieveResponse, named_schedule, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_update(self, async_client: AsyncMetronome) -> None: - named_schedule = await async_client.v1.contracts.named_schedules.update( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - schedule_name="my-schedule", - starting_at=parse_datetime("2022-02-01T00:00:00Z"), - value={"my_key": "my_value"}, - ) - assert named_schedule is None - - @parametrize - async def test_method_update_with_all_params(self, async_client: AsyncMetronome) -> None: - named_schedule = await async_client.v1.contracts.named_schedules.update( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - schedule_name="my-schedule", - starting_at=parse_datetime("2022-02-01T00:00:00Z"), - value={"my_key": "my_value"}, - ending_before=parse_datetime("2022-02-15T00:00:00Z"), - ) - assert named_schedule is None - - @parametrize - async def test_raw_response_update(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.named_schedules.with_raw_response.update( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - schedule_name="my-schedule", - starting_at=parse_datetime("2022-02-01T00:00:00Z"), - value={"my_key": "my_value"}, - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - named_schedule = await response.parse() - assert named_schedule is None - - @parametrize - async def test_streaming_response_update(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.named_schedules.with_streaming_response.update( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - schedule_name="my-schedule", - starting_at=parse_datetime("2022-02-01T00:00:00Z"), - value={"my_key": "my_value"}, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - named_schedule = await response.parse() - assert named_schedule is None - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v1/contracts/test_products.py b/tests/api_resources/v1/contracts/test_products.py deleted file mode 100644 index b692b5248..000000000 --- a/tests/api_resources/v1/contracts/test_products.py +++ /dev/null @@ -1,472 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome._utils import parse_datetime -from metronome.pagination import SyncCursorPage, AsyncCursorPage -from metronome.types.v1.contracts import ( - ProductListResponse, - ProductCreateResponse, - ProductUpdateResponse, - ProductArchiveResponse, - ProductRetrieveResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestProducts: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Metronome) -> None: - product = client.v1.contracts.products.create( - name="My Product", - type="USAGE", - ) - assert_matches_type(ProductCreateResponse, product, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Metronome) -> None: - product = client.v1.contracts.products.create( - name="My Product", - type="USAGE", - billable_metric_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - composite_product_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - composite_tags=["string"], - custom_fields={"foo": "string"}, - exclude_free_usage=True, - is_refundable=True, - netsuite_internal_item_id="netsuite_internal_item_id", - netsuite_overage_item_id="netsuite_overage_item_id", - presentation_group_key=["string"], - pricing_group_key=["string"], - quantity_conversion={ - "conversion_factor": 0, - "operation": "MULTIPLY", - "name": "name", - }, - quantity_rounding={ - "decimal_places": 0, - "rounding_method": "ROUND_UP", - }, - tags=["string"], - ) - assert_matches_type(ProductCreateResponse, product, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Metronome) -> None: - response = client.v1.contracts.products.with_raw_response.create( - name="My Product", - type="USAGE", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - product = response.parse() - assert_matches_type(ProductCreateResponse, product, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Metronome) -> None: - with client.v1.contracts.products.with_streaming_response.create( - name="My Product", - type="USAGE", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - product = response.parse() - assert_matches_type(ProductCreateResponse, product, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_retrieve(self, client: Metronome) -> None: - product = client.v1.contracts.products.retrieve( - id="d84e7f4e-7a70-4fe4-be02-7a5027beffcc", - ) - assert_matches_type(ProductRetrieveResponse, product, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Metronome) -> None: - response = client.v1.contracts.products.with_raw_response.retrieve( - id="d84e7f4e-7a70-4fe4-be02-7a5027beffcc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - product = response.parse() - assert_matches_type(ProductRetrieveResponse, product, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Metronome) -> None: - with client.v1.contracts.products.with_streaming_response.retrieve( - id="d84e7f4e-7a70-4fe4-be02-7a5027beffcc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - product = response.parse() - assert_matches_type(ProductRetrieveResponse, product, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_update(self, client: Metronome) -> None: - product = client.v1.contracts.products.update( - product_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) - assert_matches_type(ProductUpdateResponse, product, path=["response"]) - - @parametrize - def test_method_update_with_all_params(self, client: Metronome) -> None: - product = client.v1.contracts.products.update( - product_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - billable_metric_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - composite_product_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - composite_tags=["string"], - exclude_free_usage=True, - is_refundable=True, - name="My Updated Product", - netsuite_internal_item_id="netsuite_internal_item_id", - netsuite_overage_item_id="netsuite_overage_item_id", - presentation_group_key=["string"], - pricing_group_key=["string"], - quantity_conversion={ - "conversion_factor": 0, - "operation": "MULTIPLY", - "name": "name", - }, - quantity_rounding={ - "decimal_places": 0, - "rounding_method": "ROUND_UP", - }, - tags=["string"], - ) - assert_matches_type(ProductUpdateResponse, product, path=["response"]) - - @parametrize - def test_raw_response_update(self, client: Metronome) -> None: - response = client.v1.contracts.products.with_raw_response.update( - product_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - product = response.parse() - assert_matches_type(ProductUpdateResponse, product, path=["response"]) - - @parametrize - def test_streaming_response_update(self, client: Metronome) -> None: - with client.v1.contracts.products.with_streaming_response.update( - product_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - product = response.parse() - assert_matches_type(ProductUpdateResponse, product, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_list(self, client: Metronome) -> None: - product = client.v1.contracts.products.list() - assert_matches_type(SyncCursorPage[ProductListResponse], product, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Metronome) -> None: - product = client.v1.contracts.products.list( - limit=1, - next_page="next_page", - archive_filter="NOT_ARCHIVED", - ) - assert_matches_type(SyncCursorPage[ProductListResponse], product, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Metronome) -> None: - response = client.v1.contracts.products.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - product = response.parse() - assert_matches_type(SyncCursorPage[ProductListResponse], product, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Metronome) -> None: - with client.v1.contracts.products.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - product = response.parse() - assert_matches_type(SyncCursorPage[ProductListResponse], product, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_archive(self, client: Metronome) -> None: - product = client.v1.contracts.products.archive( - product_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(ProductArchiveResponse, product, path=["response"]) - - @parametrize - def test_raw_response_archive(self, client: Metronome) -> None: - response = client.v1.contracts.products.with_raw_response.archive( - product_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - product = response.parse() - assert_matches_type(ProductArchiveResponse, product, path=["response"]) - - @parametrize - def test_streaming_response_archive(self, client: Metronome) -> None: - with client.v1.contracts.products.with_streaming_response.archive( - product_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - product = response.parse() - assert_matches_type(ProductArchiveResponse, product, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncProducts: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncMetronome) -> None: - product = await async_client.v1.contracts.products.create( - name="My Product", - type="USAGE", - ) - assert_matches_type(ProductCreateResponse, product, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncMetronome) -> None: - product = await async_client.v1.contracts.products.create( - name="My Product", - type="USAGE", - billable_metric_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - composite_product_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - composite_tags=["string"], - custom_fields={"foo": "string"}, - exclude_free_usage=True, - is_refundable=True, - netsuite_internal_item_id="netsuite_internal_item_id", - netsuite_overage_item_id="netsuite_overage_item_id", - presentation_group_key=["string"], - pricing_group_key=["string"], - quantity_conversion={ - "conversion_factor": 0, - "operation": "MULTIPLY", - "name": "name", - }, - quantity_rounding={ - "decimal_places": 0, - "rounding_method": "ROUND_UP", - }, - tags=["string"], - ) - assert_matches_type(ProductCreateResponse, product, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.products.with_raw_response.create( - name="My Product", - type="USAGE", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - product = await response.parse() - assert_matches_type(ProductCreateResponse, product, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.products.with_streaming_response.create( - name="My Product", - type="USAGE", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - product = await response.parse() - assert_matches_type(ProductCreateResponse, product, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_retrieve(self, async_client: AsyncMetronome) -> None: - product = await async_client.v1.contracts.products.retrieve( - id="d84e7f4e-7a70-4fe4-be02-7a5027beffcc", - ) - assert_matches_type(ProductRetrieveResponse, product, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.products.with_raw_response.retrieve( - id="d84e7f4e-7a70-4fe4-be02-7a5027beffcc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - product = await response.parse() - assert_matches_type(ProductRetrieveResponse, product, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.products.with_streaming_response.retrieve( - id="d84e7f4e-7a70-4fe4-be02-7a5027beffcc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - product = await response.parse() - assert_matches_type(ProductRetrieveResponse, product, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_update(self, async_client: AsyncMetronome) -> None: - product = await async_client.v1.contracts.products.update( - product_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) - assert_matches_type(ProductUpdateResponse, product, path=["response"]) - - @parametrize - async def test_method_update_with_all_params(self, async_client: AsyncMetronome) -> None: - product = await async_client.v1.contracts.products.update( - product_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - billable_metric_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - composite_product_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - composite_tags=["string"], - exclude_free_usage=True, - is_refundable=True, - name="My Updated Product", - netsuite_internal_item_id="netsuite_internal_item_id", - netsuite_overage_item_id="netsuite_overage_item_id", - presentation_group_key=["string"], - pricing_group_key=["string"], - quantity_conversion={ - "conversion_factor": 0, - "operation": "MULTIPLY", - "name": "name", - }, - quantity_rounding={ - "decimal_places": 0, - "rounding_method": "ROUND_UP", - }, - tags=["string"], - ) - assert_matches_type(ProductUpdateResponse, product, path=["response"]) - - @parametrize - async def test_raw_response_update(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.products.with_raw_response.update( - product_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - product = await response.parse() - assert_matches_type(ProductUpdateResponse, product, path=["response"]) - - @parametrize - async def test_streaming_response_update(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.products.with_streaming_response.update( - product_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - product = await response.parse() - assert_matches_type(ProductUpdateResponse, product, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_list(self, async_client: AsyncMetronome) -> None: - product = await async_client.v1.contracts.products.list() - assert_matches_type(AsyncCursorPage[ProductListResponse], product, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncMetronome) -> None: - product = await async_client.v1.contracts.products.list( - limit=1, - next_page="next_page", - archive_filter="NOT_ARCHIVED", - ) - assert_matches_type(AsyncCursorPage[ProductListResponse], product, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.products.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - product = await response.parse() - assert_matches_type(AsyncCursorPage[ProductListResponse], product, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.products.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - product = await response.parse() - assert_matches_type(AsyncCursorPage[ProductListResponse], product, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_archive(self, async_client: AsyncMetronome) -> None: - product = await async_client.v1.contracts.products.archive( - product_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(ProductArchiveResponse, product, path=["response"]) - - @parametrize - async def test_raw_response_archive(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.products.with_raw_response.archive( - product_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - product = await response.parse() - assert_matches_type(ProductArchiveResponse, product, path=["response"]) - - @parametrize - async def test_streaming_response_archive(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.products.with_streaming_response.archive( - product_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - product = await response.parse() - assert_matches_type(ProductArchiveResponse, product, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v1/contracts/test_rate_cards.py b/tests/api_resources/v1/contracts/test_rate_cards.py deleted file mode 100644 index 554de4980..000000000 --- a/tests/api_resources/v1/contracts/test_rate_cards.py +++ /dev/null @@ -1,539 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome._utils import parse_datetime -from metronome.pagination import SyncCursorPage, AsyncCursorPage -from metronome.types.v1.contracts import ( - RateCardListResponse, - RateCardCreateResponse, - RateCardUpdateResponse, - RateCardArchiveResponse, - RateCardRetrieveResponse, - RateCardRetrieveRateScheduleResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestRateCards: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Metronome) -> None: - rate_card = client.v1.contracts.rate_cards.create( - name="My Rate Card", - ) - assert_matches_type(RateCardCreateResponse, rate_card, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Metronome) -> None: - rate_card = client.v1.contracts.rate_cards.create( - name="My Rate Card", - aliases=[ - { - "name": "my-rate-card", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - credit_type_conversions=[ - { - "custom_credit_type_id": "2714e483-4ff1-48e4-9e25-ac732e8f24f2", - "fiat_per_custom_credit": 2, - } - ], - custom_fields={"foo": "string"}, - description="My Rate Card Description", - fiat_credit_type_id="2714e483-4ff1-48e4-9e25-ac732e8f24f2", - ) - assert_matches_type(RateCardCreateResponse, rate_card, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Metronome) -> None: - response = client.v1.contracts.rate_cards.with_raw_response.create( - name="My Rate Card", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - rate_card = response.parse() - assert_matches_type(RateCardCreateResponse, rate_card, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Metronome) -> None: - with client.v1.contracts.rate_cards.with_streaming_response.create( - name="My Rate Card", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - rate_card = response.parse() - assert_matches_type(RateCardCreateResponse, rate_card, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_retrieve(self, client: Metronome) -> None: - rate_card = client.v1.contracts.rate_cards.retrieve( - id="f3d51ae8-f283-44e1-9933-a3cf9ad7a6fe", - ) - assert_matches_type(RateCardRetrieveResponse, rate_card, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Metronome) -> None: - response = client.v1.contracts.rate_cards.with_raw_response.retrieve( - id="f3d51ae8-f283-44e1-9933-a3cf9ad7a6fe", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - rate_card = response.parse() - assert_matches_type(RateCardRetrieveResponse, rate_card, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Metronome) -> None: - with client.v1.contracts.rate_cards.with_streaming_response.retrieve( - id="f3d51ae8-f283-44e1-9933-a3cf9ad7a6fe", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - rate_card = response.parse() - assert_matches_type(RateCardRetrieveResponse, rate_card, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_update(self, client: Metronome) -> None: - rate_card = client.v1.contracts.rate_cards.update( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(RateCardUpdateResponse, rate_card, path=["response"]) - - @parametrize - def test_method_update_with_all_params(self, client: Metronome) -> None: - rate_card = client.v1.contracts.rate_cards.update( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - aliases=[ - { - "name": "name", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - description="My Updated Rate Card Description", - name="My Updated Rate Card", - ) - assert_matches_type(RateCardUpdateResponse, rate_card, path=["response"]) - - @parametrize - def test_raw_response_update(self, client: Metronome) -> None: - response = client.v1.contracts.rate_cards.with_raw_response.update( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - rate_card = response.parse() - assert_matches_type(RateCardUpdateResponse, rate_card, path=["response"]) - - @parametrize - def test_streaming_response_update(self, client: Metronome) -> None: - with client.v1.contracts.rate_cards.with_streaming_response.update( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - rate_card = response.parse() - assert_matches_type(RateCardUpdateResponse, rate_card, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_list(self, client: Metronome) -> None: - rate_card = client.v1.contracts.rate_cards.list() - assert_matches_type(SyncCursorPage[RateCardListResponse], rate_card, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Metronome) -> None: - rate_card = client.v1.contracts.rate_cards.list( - limit=1, - next_page="next_page", - body={}, - ) - assert_matches_type(SyncCursorPage[RateCardListResponse], rate_card, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Metronome) -> None: - response = client.v1.contracts.rate_cards.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - rate_card = response.parse() - assert_matches_type(SyncCursorPage[RateCardListResponse], rate_card, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Metronome) -> None: - with client.v1.contracts.rate_cards.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - rate_card = response.parse() - assert_matches_type(SyncCursorPage[RateCardListResponse], rate_card, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_archive(self, client: Metronome) -> None: - rate_card = client.v1.contracts.rate_cards.archive( - id="12b21470-4570-40df-8998-449d0b0bc52f", - ) - assert_matches_type(RateCardArchiveResponse, rate_card, path=["response"]) - - @parametrize - def test_raw_response_archive(self, client: Metronome) -> None: - response = client.v1.contracts.rate_cards.with_raw_response.archive( - id="12b21470-4570-40df-8998-449d0b0bc52f", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - rate_card = response.parse() - assert_matches_type(RateCardArchiveResponse, rate_card, path=["response"]) - - @parametrize - def test_streaming_response_archive(self, client: Metronome) -> None: - with client.v1.contracts.rate_cards.with_streaming_response.archive( - id="12b21470-4570-40df-8998-449d0b0bc52f", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - rate_card = response.parse() - assert_matches_type(RateCardArchiveResponse, rate_card, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_retrieve_rate_schedule(self, client: Metronome) -> None: - rate_card = client.v1.contracts.rate_cards.retrieve_rate_schedule( - rate_card_id="f3d51ae8-f283-44e1-9933-a3cf9ad7a6fe", - starting_at=parse_datetime("2024-01-01T00:00:00.000Z"), - ) - assert_matches_type(RateCardRetrieveRateScheduleResponse, rate_card, path=["response"]) - - @parametrize - def test_method_retrieve_rate_schedule_with_all_params(self, client: Metronome) -> None: - rate_card = client.v1.contracts.rate_cards.retrieve_rate_schedule( - rate_card_id="f3d51ae8-f283-44e1-9933-a3cf9ad7a6fe", - starting_at=parse_datetime("2024-01-01T00:00:00.000Z"), - limit=1, - next_page="next_page", - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - selectors=[ - { - "billing_frequency": "MONTHLY", - "partial_pricing_group_values": { - "region": "us-west-2", - "cloud": "aws", - }, - "pricing_group_values": {"foo": "string"}, - "product_id": "d6300dbb-882e-4d2d-8dec-5125d16b65d0", - } - ], - ) - assert_matches_type(RateCardRetrieveRateScheduleResponse, rate_card, path=["response"]) - - @parametrize - def test_raw_response_retrieve_rate_schedule(self, client: Metronome) -> None: - response = client.v1.contracts.rate_cards.with_raw_response.retrieve_rate_schedule( - rate_card_id="f3d51ae8-f283-44e1-9933-a3cf9ad7a6fe", - starting_at=parse_datetime("2024-01-01T00:00:00.000Z"), - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - rate_card = response.parse() - assert_matches_type(RateCardRetrieveRateScheduleResponse, rate_card, path=["response"]) - - @parametrize - def test_streaming_response_retrieve_rate_schedule(self, client: Metronome) -> None: - with client.v1.contracts.rate_cards.with_streaming_response.retrieve_rate_schedule( - rate_card_id="f3d51ae8-f283-44e1-9933-a3cf9ad7a6fe", - starting_at=parse_datetime("2024-01-01T00:00:00.000Z"), - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - rate_card = response.parse() - assert_matches_type(RateCardRetrieveRateScheduleResponse, rate_card, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncRateCards: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncMetronome) -> None: - rate_card = await async_client.v1.contracts.rate_cards.create( - name="My Rate Card", - ) - assert_matches_type(RateCardCreateResponse, rate_card, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncMetronome) -> None: - rate_card = await async_client.v1.contracts.rate_cards.create( - name="My Rate Card", - aliases=[ - { - "name": "my-rate-card", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - credit_type_conversions=[ - { - "custom_credit_type_id": "2714e483-4ff1-48e4-9e25-ac732e8f24f2", - "fiat_per_custom_credit": 2, - } - ], - custom_fields={"foo": "string"}, - description="My Rate Card Description", - fiat_credit_type_id="2714e483-4ff1-48e4-9e25-ac732e8f24f2", - ) - assert_matches_type(RateCardCreateResponse, rate_card, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.rate_cards.with_raw_response.create( - name="My Rate Card", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - rate_card = await response.parse() - assert_matches_type(RateCardCreateResponse, rate_card, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.rate_cards.with_streaming_response.create( - name="My Rate Card", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - rate_card = await response.parse() - assert_matches_type(RateCardCreateResponse, rate_card, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_retrieve(self, async_client: AsyncMetronome) -> None: - rate_card = await async_client.v1.contracts.rate_cards.retrieve( - id="f3d51ae8-f283-44e1-9933-a3cf9ad7a6fe", - ) - assert_matches_type(RateCardRetrieveResponse, rate_card, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.rate_cards.with_raw_response.retrieve( - id="f3d51ae8-f283-44e1-9933-a3cf9ad7a6fe", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - rate_card = await response.parse() - assert_matches_type(RateCardRetrieveResponse, rate_card, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.rate_cards.with_streaming_response.retrieve( - id="f3d51ae8-f283-44e1-9933-a3cf9ad7a6fe", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - rate_card = await response.parse() - assert_matches_type(RateCardRetrieveResponse, rate_card, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_update(self, async_client: AsyncMetronome) -> None: - rate_card = await async_client.v1.contracts.rate_cards.update( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(RateCardUpdateResponse, rate_card, path=["response"]) - - @parametrize - async def test_method_update_with_all_params(self, async_client: AsyncMetronome) -> None: - rate_card = await async_client.v1.contracts.rate_cards.update( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - aliases=[ - { - "name": "name", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - description="My Updated Rate Card Description", - name="My Updated Rate Card", - ) - assert_matches_type(RateCardUpdateResponse, rate_card, path=["response"]) - - @parametrize - async def test_raw_response_update(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.rate_cards.with_raw_response.update( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - rate_card = await response.parse() - assert_matches_type(RateCardUpdateResponse, rate_card, path=["response"]) - - @parametrize - async def test_streaming_response_update(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.rate_cards.with_streaming_response.update( - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - rate_card = await response.parse() - assert_matches_type(RateCardUpdateResponse, rate_card, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_list(self, async_client: AsyncMetronome) -> None: - rate_card = await async_client.v1.contracts.rate_cards.list() - assert_matches_type(AsyncCursorPage[RateCardListResponse], rate_card, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncMetronome) -> None: - rate_card = await async_client.v1.contracts.rate_cards.list( - limit=1, - next_page="next_page", - body={}, - ) - assert_matches_type(AsyncCursorPage[RateCardListResponse], rate_card, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.rate_cards.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - rate_card = await response.parse() - assert_matches_type(AsyncCursorPage[RateCardListResponse], rate_card, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.rate_cards.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - rate_card = await response.parse() - assert_matches_type(AsyncCursorPage[RateCardListResponse], rate_card, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_archive(self, async_client: AsyncMetronome) -> None: - rate_card = await async_client.v1.contracts.rate_cards.archive( - id="12b21470-4570-40df-8998-449d0b0bc52f", - ) - assert_matches_type(RateCardArchiveResponse, rate_card, path=["response"]) - - @parametrize - async def test_raw_response_archive(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.rate_cards.with_raw_response.archive( - id="12b21470-4570-40df-8998-449d0b0bc52f", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - rate_card = await response.parse() - assert_matches_type(RateCardArchiveResponse, rate_card, path=["response"]) - - @parametrize - async def test_streaming_response_archive(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.rate_cards.with_streaming_response.archive( - id="12b21470-4570-40df-8998-449d0b0bc52f", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - rate_card = await response.parse() - assert_matches_type(RateCardArchiveResponse, rate_card, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_retrieve_rate_schedule(self, async_client: AsyncMetronome) -> None: - rate_card = await async_client.v1.contracts.rate_cards.retrieve_rate_schedule( - rate_card_id="f3d51ae8-f283-44e1-9933-a3cf9ad7a6fe", - starting_at=parse_datetime("2024-01-01T00:00:00.000Z"), - ) - assert_matches_type(RateCardRetrieveRateScheduleResponse, rate_card, path=["response"]) - - @parametrize - async def test_method_retrieve_rate_schedule_with_all_params(self, async_client: AsyncMetronome) -> None: - rate_card = await async_client.v1.contracts.rate_cards.retrieve_rate_schedule( - rate_card_id="f3d51ae8-f283-44e1-9933-a3cf9ad7a6fe", - starting_at=parse_datetime("2024-01-01T00:00:00.000Z"), - limit=1, - next_page="next_page", - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - selectors=[ - { - "billing_frequency": "MONTHLY", - "partial_pricing_group_values": { - "region": "us-west-2", - "cloud": "aws", - }, - "pricing_group_values": {"foo": "string"}, - "product_id": "d6300dbb-882e-4d2d-8dec-5125d16b65d0", - } - ], - ) - assert_matches_type(RateCardRetrieveRateScheduleResponse, rate_card, path=["response"]) - - @parametrize - async def test_raw_response_retrieve_rate_schedule(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.rate_cards.with_raw_response.retrieve_rate_schedule( - rate_card_id="f3d51ae8-f283-44e1-9933-a3cf9ad7a6fe", - starting_at=parse_datetime("2024-01-01T00:00:00.000Z"), - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - rate_card = await response.parse() - assert_matches_type(RateCardRetrieveRateScheduleResponse, rate_card, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve_rate_schedule(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.rate_cards.with_streaming_response.retrieve_rate_schedule( - rate_card_id="f3d51ae8-f283-44e1-9933-a3cf9ad7a6fe", - starting_at=parse_datetime("2024-01-01T00:00:00.000Z"), - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - rate_card = await response.parse() - assert_matches_type(RateCardRetrieveRateScheduleResponse, rate_card, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v1/customers/__init__.py b/tests/api_resources/v1/customers/__init__.py deleted file mode 100644 index fd8019a9a..000000000 --- a/tests/api_resources/v1/customers/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/v1/customers/test_alerts.py b/tests/api_resources/v1/customers/test_alerts.py deleted file mode 100644 index 8084799bb..000000000 --- a/tests/api_resources/v1/customers/test_alerts.py +++ /dev/null @@ -1,282 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome.pagination import SyncCursorPageWithoutLimit, AsyncCursorPageWithoutLimit -from metronome.types.v1.customers import ( - CustomerAlert, - AlertRetrieveResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestAlerts: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_retrieve(self, client: Metronome) -> None: - alert = client.v1.customers.alerts.retrieve( - alert_id="8deed800-1b7a-495d-a207-6c52bac54dc9", - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) - assert_matches_type(AlertRetrieveResponse, alert, path=["response"]) - - @parametrize - def test_method_retrieve_with_all_params(self, client: Metronome) -> None: - alert = client.v1.customers.alerts.retrieve( - alert_id="8deed800-1b7a-495d-a207-6c52bac54dc9", - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - group_values=[ - { - "key": "key", - "value": "value", - } - ], - plans_or_contracts="PLANS", - seat_filter={ - "seat_group_key": "seat_group_key", - "seat_group_value": "seat_group_value", - }, - ) - assert_matches_type(AlertRetrieveResponse, alert, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Metronome) -> None: - response = client.v1.customers.alerts.with_raw_response.retrieve( - alert_id="8deed800-1b7a-495d-a207-6c52bac54dc9", - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - alert = response.parse() - assert_matches_type(AlertRetrieveResponse, alert, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Metronome) -> None: - with client.v1.customers.alerts.with_streaming_response.retrieve( - alert_id="8deed800-1b7a-495d-a207-6c52bac54dc9", - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - alert = response.parse() - assert_matches_type(AlertRetrieveResponse, alert, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_list(self, client: Metronome) -> None: - alert = client.v1.customers.alerts.list( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) - assert_matches_type(SyncCursorPageWithoutLimit[CustomerAlert], alert, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Metronome) -> None: - alert = client.v1.customers.alerts.list( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - next_page="next_page", - alert_statuses=["ENABLED"], - ) - assert_matches_type(SyncCursorPageWithoutLimit[CustomerAlert], alert, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Metronome) -> None: - response = client.v1.customers.alerts.with_raw_response.list( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - alert = response.parse() - assert_matches_type(SyncCursorPageWithoutLimit[CustomerAlert], alert, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Metronome) -> None: - with client.v1.customers.alerts.with_streaming_response.list( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - alert = response.parse() - assert_matches_type(SyncCursorPageWithoutLimit[CustomerAlert], alert, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_reset(self, client: Metronome) -> None: - alert = client.v1.customers.alerts.reset( - alert_id="5e8691bf-b22a-4672-922d-f80eee940f01", - customer_id="4c83caf3-8af4-44e2-9aeb-e290531726d9", - ) - assert alert is None - - @parametrize - def test_raw_response_reset(self, client: Metronome) -> None: - response = client.v1.customers.alerts.with_raw_response.reset( - alert_id="5e8691bf-b22a-4672-922d-f80eee940f01", - customer_id="4c83caf3-8af4-44e2-9aeb-e290531726d9", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - alert = response.parse() - assert alert is None - - @parametrize - def test_streaming_response_reset(self, client: Metronome) -> None: - with client.v1.customers.alerts.with_streaming_response.reset( - alert_id="5e8691bf-b22a-4672-922d-f80eee940f01", - customer_id="4c83caf3-8af4-44e2-9aeb-e290531726d9", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - alert = response.parse() - assert alert is None - - assert cast(Any, response.is_closed) is True - - -class TestAsyncAlerts: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_retrieve(self, async_client: AsyncMetronome) -> None: - alert = await async_client.v1.customers.alerts.retrieve( - alert_id="8deed800-1b7a-495d-a207-6c52bac54dc9", - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) - assert_matches_type(AlertRetrieveResponse, alert, path=["response"]) - - @parametrize - async def test_method_retrieve_with_all_params(self, async_client: AsyncMetronome) -> None: - alert = await async_client.v1.customers.alerts.retrieve( - alert_id="8deed800-1b7a-495d-a207-6c52bac54dc9", - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - group_values=[ - { - "key": "key", - "value": "value", - } - ], - plans_or_contracts="PLANS", - seat_filter={ - "seat_group_key": "seat_group_key", - "seat_group_value": "seat_group_value", - }, - ) - assert_matches_type(AlertRetrieveResponse, alert, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.alerts.with_raw_response.retrieve( - alert_id="8deed800-1b7a-495d-a207-6c52bac54dc9", - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - alert = await response.parse() - assert_matches_type(AlertRetrieveResponse, alert, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.alerts.with_streaming_response.retrieve( - alert_id="8deed800-1b7a-495d-a207-6c52bac54dc9", - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - alert = await response.parse() - assert_matches_type(AlertRetrieveResponse, alert, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_list(self, async_client: AsyncMetronome) -> None: - alert = await async_client.v1.customers.alerts.list( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) - assert_matches_type(AsyncCursorPageWithoutLimit[CustomerAlert], alert, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncMetronome) -> None: - alert = await async_client.v1.customers.alerts.list( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - next_page="next_page", - alert_statuses=["ENABLED"], - ) - assert_matches_type(AsyncCursorPageWithoutLimit[CustomerAlert], alert, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.alerts.with_raw_response.list( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - alert = await response.parse() - assert_matches_type(AsyncCursorPageWithoutLimit[CustomerAlert], alert, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.alerts.with_streaming_response.list( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - alert = await response.parse() - assert_matches_type(AsyncCursorPageWithoutLimit[CustomerAlert], alert, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_reset(self, async_client: AsyncMetronome) -> None: - alert = await async_client.v1.customers.alerts.reset( - alert_id="5e8691bf-b22a-4672-922d-f80eee940f01", - customer_id="4c83caf3-8af4-44e2-9aeb-e290531726d9", - ) - assert alert is None - - @parametrize - async def test_raw_response_reset(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.alerts.with_raw_response.reset( - alert_id="5e8691bf-b22a-4672-922d-f80eee940f01", - customer_id="4c83caf3-8af4-44e2-9aeb-e290531726d9", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - alert = await response.parse() - assert alert is None - - @parametrize - async def test_streaming_response_reset(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.alerts.with_streaming_response.reset( - alert_id="5e8691bf-b22a-4672-922d-f80eee940f01", - customer_id="4c83caf3-8af4-44e2-9aeb-e290531726d9", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - alert = await response.parse() - assert alert is None - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v1/customers/test_billing_config.py b/tests/api_resources/v1/customers/test_billing_config.py deleted file mode 100644 index 870400d39..000000000 --- a/tests/api_resources/v1/customers/test_billing_config.py +++ /dev/null @@ -1,312 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome.types.v1.customers import BillingConfigRetrieveResponse - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestBillingConfig: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Metronome) -> None: - billing_config = client.v1.customers.billing_config.create( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - billing_provider_type="stripe", - billing_provider_customer_id="cus_AJ6y20bjkOOayM", - ) - assert billing_config is None - - @parametrize - def test_method_create_with_all_params(self, client: Metronome) -> None: - billing_config = client.v1.customers.billing_config.create( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - billing_provider_type="stripe", - billing_provider_customer_id="cus_AJ6y20bjkOOayM", - aws_customer_account_id="aws_customer_account_id", - aws_customer_id="aws_customer_id", - aws_product_code="aws_product_code", - aws_region="af-south-1", - stripe_collection_method="charge_automatically", - ) - assert billing_config is None - - @parametrize - def test_raw_response_create(self, client: Metronome) -> None: - response = client.v1.customers.billing_config.with_raw_response.create( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - billing_provider_type="stripe", - billing_provider_customer_id="cus_AJ6y20bjkOOayM", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - billing_config = response.parse() - assert billing_config is None - - @parametrize - def test_streaming_response_create(self, client: Metronome) -> None: - with client.v1.customers.billing_config.with_streaming_response.create( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - billing_provider_type="stripe", - billing_provider_customer_id="cus_AJ6y20bjkOOayM", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - billing_config = response.parse() - assert billing_config is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_create(self, client: Metronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - client.v1.customers.billing_config.with_raw_response.create( - customer_id="", - billing_provider_type="stripe", - billing_provider_customer_id="cus_AJ6y20bjkOOayM", - ) - - @parametrize - def test_method_retrieve(self, client: Metronome) -> None: - billing_config = client.v1.customers.billing_config.retrieve( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - billing_provider_type="stripe", - ) - assert_matches_type(BillingConfigRetrieveResponse, billing_config, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Metronome) -> None: - response = client.v1.customers.billing_config.with_raw_response.retrieve( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - billing_provider_type="stripe", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - billing_config = response.parse() - assert_matches_type(BillingConfigRetrieveResponse, billing_config, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Metronome) -> None: - with client.v1.customers.billing_config.with_streaming_response.retrieve( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - billing_provider_type="stripe", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - billing_config = response.parse() - assert_matches_type(BillingConfigRetrieveResponse, billing_config, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_retrieve(self, client: Metronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - client.v1.customers.billing_config.with_raw_response.retrieve( - customer_id="", - billing_provider_type="stripe", - ) - - @parametrize - def test_method_delete(self, client: Metronome) -> None: - billing_config = client.v1.customers.billing_config.delete( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - billing_provider_type="stripe", - ) - assert billing_config is None - - @parametrize - def test_raw_response_delete(self, client: Metronome) -> None: - response = client.v1.customers.billing_config.with_raw_response.delete( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - billing_provider_type="stripe", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - billing_config = response.parse() - assert billing_config is None - - @parametrize - def test_streaming_response_delete(self, client: Metronome) -> None: - with client.v1.customers.billing_config.with_streaming_response.delete( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - billing_provider_type="stripe", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - billing_config = response.parse() - assert billing_config is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_delete(self, client: Metronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - client.v1.customers.billing_config.with_raw_response.delete( - customer_id="", - billing_provider_type="stripe", - ) - - -class TestAsyncBillingConfig: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncMetronome) -> None: - billing_config = await async_client.v1.customers.billing_config.create( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - billing_provider_type="stripe", - billing_provider_customer_id="cus_AJ6y20bjkOOayM", - ) - assert billing_config is None - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncMetronome) -> None: - billing_config = await async_client.v1.customers.billing_config.create( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - billing_provider_type="stripe", - billing_provider_customer_id="cus_AJ6y20bjkOOayM", - aws_customer_account_id="aws_customer_account_id", - aws_customer_id="aws_customer_id", - aws_product_code="aws_product_code", - aws_region="af-south-1", - stripe_collection_method="charge_automatically", - ) - assert billing_config is None - - @parametrize - async def test_raw_response_create(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.billing_config.with_raw_response.create( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - billing_provider_type="stripe", - billing_provider_customer_id="cus_AJ6y20bjkOOayM", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - billing_config = await response.parse() - assert billing_config is None - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.billing_config.with_streaming_response.create( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - billing_provider_type="stripe", - billing_provider_customer_id="cus_AJ6y20bjkOOayM", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - billing_config = await response.parse() - assert billing_config is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_create(self, async_client: AsyncMetronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - await async_client.v1.customers.billing_config.with_raw_response.create( - customer_id="", - billing_provider_type="stripe", - billing_provider_customer_id="cus_AJ6y20bjkOOayM", - ) - - @parametrize - async def test_method_retrieve(self, async_client: AsyncMetronome) -> None: - billing_config = await async_client.v1.customers.billing_config.retrieve( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - billing_provider_type="stripe", - ) - assert_matches_type(BillingConfigRetrieveResponse, billing_config, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.billing_config.with_raw_response.retrieve( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - billing_provider_type="stripe", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - billing_config = await response.parse() - assert_matches_type(BillingConfigRetrieveResponse, billing_config, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.billing_config.with_streaming_response.retrieve( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - billing_provider_type="stripe", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - billing_config = await response.parse() - assert_matches_type(BillingConfigRetrieveResponse, billing_config, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_retrieve(self, async_client: AsyncMetronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - await async_client.v1.customers.billing_config.with_raw_response.retrieve( - customer_id="", - billing_provider_type="stripe", - ) - - @parametrize - async def test_method_delete(self, async_client: AsyncMetronome) -> None: - billing_config = await async_client.v1.customers.billing_config.delete( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - billing_provider_type="stripe", - ) - assert billing_config is None - - @parametrize - async def test_raw_response_delete(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.billing_config.with_raw_response.delete( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - billing_provider_type="stripe", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - billing_config = await response.parse() - assert billing_config is None - - @parametrize - async def test_streaming_response_delete(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.billing_config.with_streaming_response.delete( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - billing_provider_type="stripe", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - billing_config = await response.parse() - assert billing_config is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_delete(self, async_client: AsyncMetronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - await async_client.v1.customers.billing_config.with_raw_response.delete( - customer_id="", - billing_provider_type="stripe", - ) diff --git a/tests/api_resources/v1/customers/test_commits.py b/tests/api_resources/v1/customers/test_commits.py deleted file mode 100644 index 06038b46d..000000000 --- a/tests/api_resources/v1/customers/test_commits.py +++ /dev/null @@ -1,468 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome._utils import parse_datetime -from metronome.pagination import SyncBodyCursorPage, AsyncBodyCursorPage -from metronome.types.shared import Commit -from metronome.types.v1.customers import ( - CommitCreateResponse, - CommitUpdateEndDateResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestCommits: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Metronome) -> None: - commit = client.v1.customers.commits.create( - access_schedule={ - "schedule_items": [ - { - "amount": 1000, - "ending_before": parse_datetime("2020-02-01T00:00:00.000Z"), - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - } - ] - }, - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - priority=100, - product_id="f14d6729-6a44-4b13-9908-9387f1918790", - type="PREPAID", - ) - assert_matches_type(CommitCreateResponse, commit, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Metronome) -> None: - commit = client.v1.customers.commits.create( - access_schedule={ - "schedule_items": [ - { - "amount": 1000, - "ending_before": parse_datetime("2020-02-01T00:00:00.000Z"), - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - } - ], - "credit_type_id": "2714e483-4ff1-48e4-9e25-ac732e8f24f2", - }, - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - priority=100, - product_id="f14d6729-6a44-4b13-9908-9387f1918790", - type="PREPAID", - applicable_contract_ids=["string"], - applicable_product_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - applicable_product_tags=["string"], - custom_fields={"foo": "string"}, - description="description", - invoice_contract_id="e57d6929-c2f1-4796-a9a8-63cedefe848d", - invoice_schedule={ - "credit_type_id": "2714e483-4ff1-48e4-9e25-ac732e8f24f2", - "do_not_invoice": False, - "recurring_schedule": { - "amount_distribution": "DIVIDED", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "frequency": "MONTHLY", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - "schedule_items": [ - { - "timestamp": parse_datetime("2020-03-01T00:00:00.000Z"), - "amount": 0, - "quantity": 1, - "unit_price": 10000000, - } - ], - }, - name="My Commit", - netsuite_sales_order_id="netsuite_sales_order_id", - rate_type="COMMIT_RATE", - salesforce_opportunity_id="salesforce_opportunity_id", - specifiers=[ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - uniqueness_key="x", - ) - assert_matches_type(CommitCreateResponse, commit, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Metronome) -> None: - response = client.v1.customers.commits.with_raw_response.create( - access_schedule={ - "schedule_items": [ - { - "amount": 1000, - "ending_before": parse_datetime("2020-02-01T00:00:00.000Z"), - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - } - ] - }, - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - priority=100, - product_id="f14d6729-6a44-4b13-9908-9387f1918790", - type="PREPAID", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - commit = response.parse() - assert_matches_type(CommitCreateResponse, commit, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Metronome) -> None: - with client.v1.customers.commits.with_streaming_response.create( - access_schedule={ - "schedule_items": [ - { - "amount": 1000, - "ending_before": parse_datetime("2020-02-01T00:00:00.000Z"), - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - } - ] - }, - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - priority=100, - product_id="f14d6729-6a44-4b13-9908-9387f1918790", - type="PREPAID", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - commit = response.parse() - assert_matches_type(CommitCreateResponse, commit, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_list(self, client: Metronome) -> None: - commit = client.v1.customers.commits.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(SyncBodyCursorPage[Commit], commit, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Metronome) -> None: - commit = client.v1.customers.commits.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - commit_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - covering_date=parse_datetime("2019-12-27T18:11:19.117Z"), - effective_before=parse_datetime("2019-12-27T18:11:19.117Z"), - include_archived=True, - include_balance=True, - include_contract_commits=True, - include_ledgers=True, - limit=1, - next_page="next_page", - starting_at=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(SyncBodyCursorPage[Commit], commit, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Metronome) -> None: - response = client.v1.customers.commits.with_raw_response.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - commit = response.parse() - assert_matches_type(SyncBodyCursorPage[Commit], commit, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Metronome) -> None: - with client.v1.customers.commits.with_streaming_response.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - commit = response.parse() - assert_matches_type(SyncBodyCursorPage[Commit], commit, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_update_end_date(self, client: Metronome) -> None: - commit = client.v1.customers.commits.update_end_date( - commit_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(CommitUpdateEndDateResponse, commit, path=["response"]) - - @parametrize - def test_method_update_end_date_with_all_params(self, client: Metronome) -> None: - commit = client.v1.customers.commits.update_end_date( - commit_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - access_ending_before=parse_datetime("2020-01-01T00:00:00.000Z"), - invoices_ending_before=parse_datetime("2020-01-01T00:00:00.000Z"), - ) - assert_matches_type(CommitUpdateEndDateResponse, commit, path=["response"]) - - @parametrize - def test_raw_response_update_end_date(self, client: Metronome) -> None: - response = client.v1.customers.commits.with_raw_response.update_end_date( - commit_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - commit = response.parse() - assert_matches_type(CommitUpdateEndDateResponse, commit, path=["response"]) - - @parametrize - def test_streaming_response_update_end_date(self, client: Metronome) -> None: - with client.v1.customers.commits.with_streaming_response.update_end_date( - commit_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - commit = response.parse() - assert_matches_type(CommitUpdateEndDateResponse, commit, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncCommits: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncMetronome) -> None: - commit = await async_client.v1.customers.commits.create( - access_schedule={ - "schedule_items": [ - { - "amount": 1000, - "ending_before": parse_datetime("2020-02-01T00:00:00.000Z"), - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - } - ] - }, - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - priority=100, - product_id="f14d6729-6a44-4b13-9908-9387f1918790", - type="PREPAID", - ) - assert_matches_type(CommitCreateResponse, commit, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncMetronome) -> None: - commit = await async_client.v1.customers.commits.create( - access_schedule={ - "schedule_items": [ - { - "amount": 1000, - "ending_before": parse_datetime("2020-02-01T00:00:00.000Z"), - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - } - ], - "credit_type_id": "2714e483-4ff1-48e4-9e25-ac732e8f24f2", - }, - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - priority=100, - product_id="f14d6729-6a44-4b13-9908-9387f1918790", - type="PREPAID", - applicable_contract_ids=["string"], - applicable_product_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - applicable_product_tags=["string"], - custom_fields={"foo": "string"}, - description="description", - invoice_contract_id="e57d6929-c2f1-4796-a9a8-63cedefe848d", - invoice_schedule={ - "credit_type_id": "2714e483-4ff1-48e4-9e25-ac732e8f24f2", - "do_not_invoice": False, - "recurring_schedule": { - "amount_distribution": "DIVIDED", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "frequency": "MONTHLY", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - "schedule_items": [ - { - "timestamp": parse_datetime("2020-03-01T00:00:00.000Z"), - "amount": 0, - "quantity": 1, - "unit_price": 10000000, - } - ], - }, - name="My Commit", - netsuite_sales_order_id="netsuite_sales_order_id", - rate_type="COMMIT_RATE", - salesforce_opportunity_id="salesforce_opportunity_id", - specifiers=[ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - uniqueness_key="x", - ) - assert_matches_type(CommitCreateResponse, commit, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.commits.with_raw_response.create( - access_schedule={ - "schedule_items": [ - { - "amount": 1000, - "ending_before": parse_datetime("2020-02-01T00:00:00.000Z"), - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - } - ] - }, - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - priority=100, - product_id="f14d6729-6a44-4b13-9908-9387f1918790", - type="PREPAID", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - commit = await response.parse() - assert_matches_type(CommitCreateResponse, commit, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.commits.with_streaming_response.create( - access_schedule={ - "schedule_items": [ - { - "amount": 1000, - "ending_before": parse_datetime("2020-02-01T00:00:00.000Z"), - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - } - ] - }, - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - priority=100, - product_id="f14d6729-6a44-4b13-9908-9387f1918790", - type="PREPAID", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - commit = await response.parse() - assert_matches_type(CommitCreateResponse, commit, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_list(self, async_client: AsyncMetronome) -> None: - commit = await async_client.v1.customers.commits.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(AsyncBodyCursorPage[Commit], commit, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncMetronome) -> None: - commit = await async_client.v1.customers.commits.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - commit_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - covering_date=parse_datetime("2019-12-27T18:11:19.117Z"), - effective_before=parse_datetime("2019-12-27T18:11:19.117Z"), - include_archived=True, - include_balance=True, - include_contract_commits=True, - include_ledgers=True, - limit=1, - next_page="next_page", - starting_at=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(AsyncBodyCursorPage[Commit], commit, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.commits.with_raw_response.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - commit = await response.parse() - assert_matches_type(AsyncBodyCursorPage[Commit], commit, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.commits.with_streaming_response.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - commit = await response.parse() - assert_matches_type(AsyncBodyCursorPage[Commit], commit, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_update_end_date(self, async_client: AsyncMetronome) -> None: - commit = await async_client.v1.customers.commits.update_end_date( - commit_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(CommitUpdateEndDateResponse, commit, path=["response"]) - - @parametrize - async def test_method_update_end_date_with_all_params(self, async_client: AsyncMetronome) -> None: - commit = await async_client.v1.customers.commits.update_end_date( - commit_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - access_ending_before=parse_datetime("2020-01-01T00:00:00.000Z"), - invoices_ending_before=parse_datetime("2020-01-01T00:00:00.000Z"), - ) - assert_matches_type(CommitUpdateEndDateResponse, commit, path=["response"]) - - @parametrize - async def test_raw_response_update_end_date(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.commits.with_raw_response.update_end_date( - commit_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - commit = await response.parse() - assert_matches_type(CommitUpdateEndDateResponse, commit, path=["response"]) - - @parametrize - async def test_streaming_response_update_end_date(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.commits.with_streaming_response.update_end_date( - commit_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - commit = await response.parse() - assert_matches_type(CommitUpdateEndDateResponse, commit, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v1/customers/test_credits.py b/tests/api_resources/v1/customers/test_credits.py deleted file mode 100644 index c7d231d55..000000000 --- a/tests/api_resources/v1/customers/test_credits.py +++ /dev/null @@ -1,402 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome._utils import parse_datetime -from metronome.pagination import SyncBodyCursorPage, AsyncBodyCursorPage -from metronome.types.shared import Credit -from metronome.types.v1.customers import ( - CreditCreateResponse, - CreditUpdateEndDateResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestCredits: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Metronome) -> None: - credit = client.v1.customers.credits.create( - access_schedule={ - "schedule_items": [ - { - "amount": 1000, - "ending_before": parse_datetime("2020-02-01T00:00:00.000Z"), - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - } - ] - }, - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - priority=100, - product_id="f14d6729-6a44-4b13-9908-9387f1918790", - ) - assert_matches_type(CreditCreateResponse, credit, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Metronome) -> None: - credit = client.v1.customers.credits.create( - access_schedule={ - "schedule_items": [ - { - "amount": 1000, - "ending_before": parse_datetime("2020-02-01T00:00:00.000Z"), - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - } - ], - "credit_type_id": "2714e483-4ff1-48e4-9e25-ac732e8f24f2", - }, - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - priority=100, - product_id="f14d6729-6a44-4b13-9908-9387f1918790", - applicable_contract_ids=["string"], - applicable_product_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - applicable_product_tags=["string"], - custom_fields={"foo": "string"}, - description="description", - name="My Credit", - netsuite_sales_order_id="netsuite_sales_order_id", - rate_type="COMMIT_RATE", - salesforce_opportunity_id="salesforce_opportunity_id", - specifiers=[ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - uniqueness_key="x", - ) - assert_matches_type(CreditCreateResponse, credit, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Metronome) -> None: - response = client.v1.customers.credits.with_raw_response.create( - access_schedule={ - "schedule_items": [ - { - "amount": 1000, - "ending_before": parse_datetime("2020-02-01T00:00:00.000Z"), - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - } - ] - }, - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - priority=100, - product_id="f14d6729-6a44-4b13-9908-9387f1918790", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - credit = response.parse() - assert_matches_type(CreditCreateResponse, credit, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Metronome) -> None: - with client.v1.customers.credits.with_streaming_response.create( - access_schedule={ - "schedule_items": [ - { - "amount": 1000, - "ending_before": parse_datetime("2020-02-01T00:00:00.000Z"), - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - } - ] - }, - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - priority=100, - product_id="f14d6729-6a44-4b13-9908-9387f1918790", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - credit = response.parse() - assert_matches_type(CreditCreateResponse, credit, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_list(self, client: Metronome) -> None: - credit = client.v1.customers.credits.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(SyncBodyCursorPage[Credit], credit, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Metronome) -> None: - credit = client.v1.customers.credits.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - covering_date=parse_datetime("2019-12-27T18:11:19.117Z"), - credit_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - effective_before=parse_datetime("2019-12-27T18:11:19.117Z"), - include_archived=True, - include_balance=True, - include_contract_credits=True, - include_ledgers=True, - limit=1, - next_page="next_page", - starting_at=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(SyncBodyCursorPage[Credit], credit, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Metronome) -> None: - response = client.v1.customers.credits.with_raw_response.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - credit = response.parse() - assert_matches_type(SyncBodyCursorPage[Credit], credit, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Metronome) -> None: - with client.v1.customers.credits.with_streaming_response.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - credit = response.parse() - assert_matches_type(SyncBodyCursorPage[Credit], credit, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_update_end_date(self, client: Metronome) -> None: - credit = client.v1.customers.credits.update_end_date( - access_ending_before=parse_datetime("2020-01-01T00:00:00.000Z"), - credit_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(CreditUpdateEndDateResponse, credit, path=["response"]) - - @parametrize - def test_raw_response_update_end_date(self, client: Metronome) -> None: - response = client.v1.customers.credits.with_raw_response.update_end_date( - access_ending_before=parse_datetime("2020-01-01T00:00:00.000Z"), - credit_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - credit = response.parse() - assert_matches_type(CreditUpdateEndDateResponse, credit, path=["response"]) - - @parametrize - def test_streaming_response_update_end_date(self, client: Metronome) -> None: - with client.v1.customers.credits.with_streaming_response.update_end_date( - access_ending_before=parse_datetime("2020-01-01T00:00:00.000Z"), - credit_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - credit = response.parse() - assert_matches_type(CreditUpdateEndDateResponse, credit, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncCredits: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncMetronome) -> None: - credit = await async_client.v1.customers.credits.create( - access_schedule={ - "schedule_items": [ - { - "amount": 1000, - "ending_before": parse_datetime("2020-02-01T00:00:00.000Z"), - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - } - ] - }, - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - priority=100, - product_id="f14d6729-6a44-4b13-9908-9387f1918790", - ) - assert_matches_type(CreditCreateResponse, credit, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncMetronome) -> None: - credit = await async_client.v1.customers.credits.create( - access_schedule={ - "schedule_items": [ - { - "amount": 1000, - "ending_before": parse_datetime("2020-02-01T00:00:00.000Z"), - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - } - ], - "credit_type_id": "2714e483-4ff1-48e4-9e25-ac732e8f24f2", - }, - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - priority=100, - product_id="f14d6729-6a44-4b13-9908-9387f1918790", - applicable_contract_ids=["string"], - applicable_product_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - applicable_product_tags=["string"], - custom_fields={"foo": "string"}, - description="description", - name="My Credit", - netsuite_sales_order_id="netsuite_sales_order_id", - rate_type="COMMIT_RATE", - salesforce_opportunity_id="salesforce_opportunity_id", - specifiers=[ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - uniqueness_key="x", - ) - assert_matches_type(CreditCreateResponse, credit, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.credits.with_raw_response.create( - access_schedule={ - "schedule_items": [ - { - "amount": 1000, - "ending_before": parse_datetime("2020-02-01T00:00:00.000Z"), - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - } - ] - }, - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - priority=100, - product_id="f14d6729-6a44-4b13-9908-9387f1918790", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - credit = await response.parse() - assert_matches_type(CreditCreateResponse, credit, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.credits.with_streaming_response.create( - access_schedule={ - "schedule_items": [ - { - "amount": 1000, - "ending_before": parse_datetime("2020-02-01T00:00:00.000Z"), - "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - } - ] - }, - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - priority=100, - product_id="f14d6729-6a44-4b13-9908-9387f1918790", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - credit = await response.parse() - assert_matches_type(CreditCreateResponse, credit, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_list(self, async_client: AsyncMetronome) -> None: - credit = await async_client.v1.customers.credits.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(AsyncBodyCursorPage[Credit], credit, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncMetronome) -> None: - credit = await async_client.v1.customers.credits.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - covering_date=parse_datetime("2019-12-27T18:11:19.117Z"), - credit_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - effective_before=parse_datetime("2019-12-27T18:11:19.117Z"), - include_archived=True, - include_balance=True, - include_contract_credits=True, - include_ledgers=True, - limit=1, - next_page="next_page", - starting_at=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(AsyncBodyCursorPage[Credit], credit, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.credits.with_raw_response.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - credit = await response.parse() - assert_matches_type(AsyncBodyCursorPage[Credit], credit, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.credits.with_streaming_response.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - credit = await response.parse() - assert_matches_type(AsyncBodyCursorPage[Credit], credit, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_update_end_date(self, async_client: AsyncMetronome) -> None: - credit = await async_client.v1.customers.credits.update_end_date( - access_ending_before=parse_datetime("2020-01-01T00:00:00.000Z"), - credit_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(CreditUpdateEndDateResponse, credit, path=["response"]) - - @parametrize - async def test_raw_response_update_end_date(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.credits.with_raw_response.update_end_date( - access_ending_before=parse_datetime("2020-01-01T00:00:00.000Z"), - credit_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - credit = await response.parse() - assert_matches_type(CreditUpdateEndDateResponse, credit, path=["response"]) - - @parametrize - async def test_streaming_response_update_end_date(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.credits.with_streaming_response.update_end_date( - access_ending_before=parse_datetime("2020-01-01T00:00:00.000Z"), - credit_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - credit = await response.parse() - assert_matches_type(CreditUpdateEndDateResponse, credit, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v1/customers/test_invoices.py b/tests/api_resources/v1/customers/test_invoices.py deleted file mode 100644 index 423f90b91..000000000 --- a/tests/api_resources/v1/customers/test_invoices.py +++ /dev/null @@ -1,647 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import httpx -import pytest -from respx import MockRouter - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome._utils import parse_datetime -from metronome._response import ( - BinaryAPIResponse, - AsyncBinaryAPIResponse, - StreamedBinaryAPIResponse, - AsyncStreamedBinaryAPIResponse, -) -from metronome.pagination import SyncCursorPage, AsyncCursorPage -from metronome.types.v1.customers import ( - Invoice, - InvoiceRetrieveResponse, - InvoiceAddChargeResponse, - InvoiceListBreakdownsResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestInvoices: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_retrieve(self, client: Metronome) -> None: - invoice = client.v1.customers.invoices.retrieve( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) - assert_matches_type(InvoiceRetrieveResponse, invoice, path=["response"]) - - @parametrize - def test_method_retrieve_with_all_params(self, client: Metronome) -> None: - invoice = client.v1.customers.invoices.retrieve( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - skip_zero_qty_line_items=True, - ) - assert_matches_type(InvoiceRetrieveResponse, invoice, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Metronome) -> None: - response = client.v1.customers.invoices.with_raw_response.retrieve( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - invoice = response.parse() - assert_matches_type(InvoiceRetrieveResponse, invoice, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Metronome) -> None: - with client.v1.customers.invoices.with_streaming_response.retrieve( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - invoice = response.parse() - assert_matches_type(InvoiceRetrieveResponse, invoice, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_retrieve(self, client: Metronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - client.v1.customers.invoices.with_raw_response.retrieve( - customer_id="", - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `invoice_id` but received ''"): - client.v1.customers.invoices.with_raw_response.retrieve( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - invoice_id="", - ) - - @parametrize - def test_method_list(self, client: Metronome) -> None: - invoice = client.v1.customers.invoices.list( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(SyncCursorPage[Invoice], invoice, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Metronome) -> None: - invoice = client.v1.customers.invoices.list( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - credit_type_id="credit_type_id", - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - limit=1, - next_page="next_page", - skip_zero_qty_line_items=True, - sort="date_asc", - starting_on=parse_datetime("2019-12-27T18:11:19.117Z"), - status="status", - ) - assert_matches_type(SyncCursorPage[Invoice], invoice, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Metronome) -> None: - response = client.v1.customers.invoices.with_raw_response.list( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - invoice = response.parse() - assert_matches_type(SyncCursorPage[Invoice], invoice, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Metronome) -> None: - with client.v1.customers.invoices.with_streaming_response.list( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - invoice = response.parse() - assert_matches_type(SyncCursorPage[Invoice], invoice, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_list(self, client: Metronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - client.v1.customers.invoices.with_raw_response.list( - customer_id="", - ) - - @parametrize - def test_method_add_charge(self, client: Metronome) -> None: - invoice = client.v1.customers.invoices.add_charge( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - charge_id="5ae4b726-1ebe-439c-9190-9831760ba195", - customer_plan_id="a23b3cf4-47fb-4c3f-bb3d-9e64f7704015", - description="One time charge", - invoice_start_timestamp=parse_datetime("2024-01-01T00:00:00Z"), - price=250, - quantity=1, - ) - assert_matches_type(InvoiceAddChargeResponse, invoice, path=["response"]) - - @parametrize - def test_raw_response_add_charge(self, client: Metronome) -> None: - response = client.v1.customers.invoices.with_raw_response.add_charge( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - charge_id="5ae4b726-1ebe-439c-9190-9831760ba195", - customer_plan_id="a23b3cf4-47fb-4c3f-bb3d-9e64f7704015", - description="One time charge", - invoice_start_timestamp=parse_datetime("2024-01-01T00:00:00Z"), - price=250, - quantity=1, - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - invoice = response.parse() - assert_matches_type(InvoiceAddChargeResponse, invoice, path=["response"]) - - @parametrize - def test_streaming_response_add_charge(self, client: Metronome) -> None: - with client.v1.customers.invoices.with_streaming_response.add_charge( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - charge_id="5ae4b726-1ebe-439c-9190-9831760ba195", - customer_plan_id="a23b3cf4-47fb-4c3f-bb3d-9e64f7704015", - description="One time charge", - invoice_start_timestamp=parse_datetime("2024-01-01T00:00:00Z"), - price=250, - quantity=1, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - invoice = response.parse() - assert_matches_type(InvoiceAddChargeResponse, invoice, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_add_charge(self, client: Metronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - client.v1.customers.invoices.with_raw_response.add_charge( - customer_id="", - charge_id="5ae4b726-1ebe-439c-9190-9831760ba195", - customer_plan_id="a23b3cf4-47fb-4c3f-bb3d-9e64f7704015", - description="One time charge", - invoice_start_timestamp=parse_datetime("2024-01-01T00:00:00Z"), - price=250, - quantity=1, - ) - - @parametrize - def test_method_list_breakdowns(self, client: Metronome) -> None: - invoice = client.v1.customers.invoices.list_breakdowns( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - starting_on=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(SyncCursorPage[InvoiceListBreakdownsResponse], invoice, path=["response"]) - - @parametrize - def test_method_list_breakdowns_with_all_params(self, client: Metronome) -> None: - invoice = client.v1.customers.invoices.list_breakdowns( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - starting_on=parse_datetime("2019-12-27T18:11:19.117Z"), - credit_type_id="credit_type_id", - limit=1, - next_page="next_page", - skip_zero_qty_line_items=True, - sort="date_asc", - status="status", - window_size="HOUR", - ) - assert_matches_type(SyncCursorPage[InvoiceListBreakdownsResponse], invoice, path=["response"]) - - @parametrize - def test_raw_response_list_breakdowns(self, client: Metronome) -> None: - response = client.v1.customers.invoices.with_raw_response.list_breakdowns( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - starting_on=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - invoice = response.parse() - assert_matches_type(SyncCursorPage[InvoiceListBreakdownsResponse], invoice, path=["response"]) - - @parametrize - def test_streaming_response_list_breakdowns(self, client: Metronome) -> None: - with client.v1.customers.invoices.with_streaming_response.list_breakdowns( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - starting_on=parse_datetime("2019-12-27T18:11:19.117Z"), - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - invoice = response.parse() - assert_matches_type(SyncCursorPage[InvoiceListBreakdownsResponse], invoice, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_list_breakdowns(self, client: Metronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - client.v1.customers.invoices.with_raw_response.list_breakdowns( - customer_id="", - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - starting_on=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - - @pytest.mark.skip(reason="prism mocking library in JS SDK doesnt support application/pdf") - @parametrize - @pytest.mark.respx(base_url=base_url) - def test_method_retrieve_pdf(self, client: Metronome, respx_mock: MockRouter) -> None: - respx_mock.get( - "/v1/customers/d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc/invoices/6a37bb88-8538-48c5-b37b-a41c836328bd/pdf" - ).mock(return_value=httpx.Response(200, json={"foo": "bar"})) - invoice = client.v1.customers.invoices.retrieve_pdf( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) - assert invoice.is_closed - assert invoice.json() == {"foo": "bar"} - assert cast(Any, invoice.is_closed) is True - assert isinstance(invoice, BinaryAPIResponse) - - @pytest.mark.skip(reason="prism mocking library in JS SDK doesnt support application/pdf") - @parametrize - @pytest.mark.respx(base_url=base_url) - def test_raw_response_retrieve_pdf(self, client: Metronome, respx_mock: MockRouter) -> None: - respx_mock.get( - "/v1/customers/d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc/invoices/6a37bb88-8538-48c5-b37b-a41c836328bd/pdf" - ).mock(return_value=httpx.Response(200, json={"foo": "bar"})) - - invoice = client.v1.customers.invoices.with_raw_response.retrieve_pdf( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) - - assert invoice.is_closed is True - assert invoice.http_request.headers.get("X-Stainless-Lang") == "python" - assert invoice.json() == {"foo": "bar"} - assert isinstance(invoice, BinaryAPIResponse) - - @pytest.mark.skip(reason="prism mocking library in JS SDK doesnt support application/pdf") - @parametrize - @pytest.mark.respx(base_url=base_url) - def test_streaming_response_retrieve_pdf(self, client: Metronome, respx_mock: MockRouter) -> None: - respx_mock.get( - "/v1/customers/d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc/invoices/6a37bb88-8538-48c5-b37b-a41c836328bd/pdf" - ).mock(return_value=httpx.Response(200, json={"foo": "bar"})) - with client.v1.customers.invoices.with_streaming_response.retrieve_pdf( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) as invoice: - assert not invoice.is_closed - assert invoice.http_request.headers.get("X-Stainless-Lang") == "python" - - assert invoice.json() == {"foo": "bar"} - assert cast(Any, invoice.is_closed) is True - assert isinstance(invoice, StreamedBinaryAPIResponse) - - assert cast(Any, invoice.is_closed) is True - - @pytest.mark.skip(reason="prism mocking library in JS SDK doesnt support application/pdf") - @parametrize - @pytest.mark.respx(base_url=base_url) - def test_path_params_retrieve_pdf(self, client: Metronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - client.v1.customers.invoices.with_raw_response.retrieve_pdf( - customer_id="", - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `invoice_id` but received ''"): - client.v1.customers.invoices.with_raw_response.retrieve_pdf( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - invoice_id="", - ) - - -class TestAsyncInvoices: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_retrieve(self, async_client: AsyncMetronome) -> None: - invoice = await async_client.v1.customers.invoices.retrieve( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) - assert_matches_type(InvoiceRetrieveResponse, invoice, path=["response"]) - - @parametrize - async def test_method_retrieve_with_all_params(self, async_client: AsyncMetronome) -> None: - invoice = await async_client.v1.customers.invoices.retrieve( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - skip_zero_qty_line_items=True, - ) - assert_matches_type(InvoiceRetrieveResponse, invoice, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.invoices.with_raw_response.retrieve( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - invoice = await response.parse() - assert_matches_type(InvoiceRetrieveResponse, invoice, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.invoices.with_streaming_response.retrieve( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - invoice = await response.parse() - assert_matches_type(InvoiceRetrieveResponse, invoice, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_retrieve(self, async_client: AsyncMetronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - await async_client.v1.customers.invoices.with_raw_response.retrieve( - customer_id="", - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `invoice_id` but received ''"): - await async_client.v1.customers.invoices.with_raw_response.retrieve( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - invoice_id="", - ) - - @parametrize - async def test_method_list(self, async_client: AsyncMetronome) -> None: - invoice = await async_client.v1.customers.invoices.list( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(AsyncCursorPage[Invoice], invoice, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncMetronome) -> None: - invoice = await async_client.v1.customers.invoices.list( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - credit_type_id="credit_type_id", - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - limit=1, - next_page="next_page", - skip_zero_qty_line_items=True, - sort="date_asc", - starting_on=parse_datetime("2019-12-27T18:11:19.117Z"), - status="status", - ) - assert_matches_type(AsyncCursorPage[Invoice], invoice, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.invoices.with_raw_response.list( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - invoice = await response.parse() - assert_matches_type(AsyncCursorPage[Invoice], invoice, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.invoices.with_streaming_response.list( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - invoice = await response.parse() - assert_matches_type(AsyncCursorPage[Invoice], invoice, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_list(self, async_client: AsyncMetronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - await async_client.v1.customers.invoices.with_raw_response.list( - customer_id="", - ) - - @parametrize - async def test_method_add_charge(self, async_client: AsyncMetronome) -> None: - invoice = await async_client.v1.customers.invoices.add_charge( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - charge_id="5ae4b726-1ebe-439c-9190-9831760ba195", - customer_plan_id="a23b3cf4-47fb-4c3f-bb3d-9e64f7704015", - description="One time charge", - invoice_start_timestamp=parse_datetime("2024-01-01T00:00:00Z"), - price=250, - quantity=1, - ) - assert_matches_type(InvoiceAddChargeResponse, invoice, path=["response"]) - - @parametrize - async def test_raw_response_add_charge(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.invoices.with_raw_response.add_charge( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - charge_id="5ae4b726-1ebe-439c-9190-9831760ba195", - customer_plan_id="a23b3cf4-47fb-4c3f-bb3d-9e64f7704015", - description="One time charge", - invoice_start_timestamp=parse_datetime("2024-01-01T00:00:00Z"), - price=250, - quantity=1, - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - invoice = await response.parse() - assert_matches_type(InvoiceAddChargeResponse, invoice, path=["response"]) - - @parametrize - async def test_streaming_response_add_charge(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.invoices.with_streaming_response.add_charge( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - charge_id="5ae4b726-1ebe-439c-9190-9831760ba195", - customer_plan_id="a23b3cf4-47fb-4c3f-bb3d-9e64f7704015", - description="One time charge", - invoice_start_timestamp=parse_datetime("2024-01-01T00:00:00Z"), - price=250, - quantity=1, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - invoice = await response.parse() - assert_matches_type(InvoiceAddChargeResponse, invoice, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_add_charge(self, async_client: AsyncMetronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - await async_client.v1.customers.invoices.with_raw_response.add_charge( - customer_id="", - charge_id="5ae4b726-1ebe-439c-9190-9831760ba195", - customer_plan_id="a23b3cf4-47fb-4c3f-bb3d-9e64f7704015", - description="One time charge", - invoice_start_timestamp=parse_datetime("2024-01-01T00:00:00Z"), - price=250, - quantity=1, - ) - - @parametrize - async def test_method_list_breakdowns(self, async_client: AsyncMetronome) -> None: - invoice = await async_client.v1.customers.invoices.list_breakdowns( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - starting_on=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(AsyncCursorPage[InvoiceListBreakdownsResponse], invoice, path=["response"]) - - @parametrize - async def test_method_list_breakdowns_with_all_params(self, async_client: AsyncMetronome) -> None: - invoice = await async_client.v1.customers.invoices.list_breakdowns( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - starting_on=parse_datetime("2019-12-27T18:11:19.117Z"), - credit_type_id="credit_type_id", - limit=1, - next_page="next_page", - skip_zero_qty_line_items=True, - sort="date_asc", - status="status", - window_size="HOUR", - ) - assert_matches_type(AsyncCursorPage[InvoiceListBreakdownsResponse], invoice, path=["response"]) - - @parametrize - async def test_raw_response_list_breakdowns(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.invoices.with_raw_response.list_breakdowns( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - starting_on=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - invoice = await response.parse() - assert_matches_type(AsyncCursorPage[InvoiceListBreakdownsResponse], invoice, path=["response"]) - - @parametrize - async def test_streaming_response_list_breakdowns(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.invoices.with_streaming_response.list_breakdowns( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - starting_on=parse_datetime("2019-12-27T18:11:19.117Z"), - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - invoice = await response.parse() - assert_matches_type(AsyncCursorPage[InvoiceListBreakdownsResponse], invoice, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_list_breakdowns(self, async_client: AsyncMetronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - await async_client.v1.customers.invoices.with_raw_response.list_breakdowns( - customer_id="", - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - starting_on=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - - @pytest.mark.skip(reason="prism mocking library in JS SDK doesnt support application/pdf") - @parametrize - @pytest.mark.respx(base_url=base_url) - async def test_method_retrieve_pdf(self, async_client: AsyncMetronome, respx_mock: MockRouter) -> None: - respx_mock.get( - "/v1/customers/d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc/invoices/6a37bb88-8538-48c5-b37b-a41c836328bd/pdf" - ).mock(return_value=httpx.Response(200, json={"foo": "bar"})) - invoice = await async_client.v1.customers.invoices.retrieve_pdf( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) - assert invoice.is_closed - assert await invoice.json() == {"foo": "bar"} - assert cast(Any, invoice.is_closed) is True - assert isinstance(invoice, AsyncBinaryAPIResponse) - - @pytest.mark.skip(reason="prism mocking library in JS SDK doesnt support application/pdf") - @parametrize - @pytest.mark.respx(base_url=base_url) - async def test_raw_response_retrieve_pdf(self, async_client: AsyncMetronome, respx_mock: MockRouter) -> None: - respx_mock.get( - "/v1/customers/d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc/invoices/6a37bb88-8538-48c5-b37b-a41c836328bd/pdf" - ).mock(return_value=httpx.Response(200, json={"foo": "bar"})) - - invoice = await async_client.v1.customers.invoices.with_raw_response.retrieve_pdf( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) - - assert invoice.is_closed is True - assert invoice.http_request.headers.get("X-Stainless-Lang") == "python" - assert await invoice.json() == {"foo": "bar"} - assert isinstance(invoice, AsyncBinaryAPIResponse) - - @pytest.mark.skip(reason="prism mocking library in JS SDK doesnt support application/pdf") - @parametrize - @pytest.mark.respx(base_url=base_url) - async def test_streaming_response_retrieve_pdf(self, async_client: AsyncMetronome, respx_mock: MockRouter) -> None: - respx_mock.get( - "/v1/customers/d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc/invoices/6a37bb88-8538-48c5-b37b-a41c836328bd/pdf" - ).mock(return_value=httpx.Response(200, json={"foo": "bar"})) - async with async_client.v1.customers.invoices.with_streaming_response.retrieve_pdf( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) as invoice: - assert not invoice.is_closed - assert invoice.http_request.headers.get("X-Stainless-Lang") == "python" - - assert await invoice.json() == {"foo": "bar"} - assert cast(Any, invoice.is_closed) is True - assert isinstance(invoice, AsyncStreamedBinaryAPIResponse) - - assert cast(Any, invoice.is_closed) is True - - @pytest.mark.skip(reason="prism mocking library in JS SDK doesnt support application/pdf") - @parametrize - @pytest.mark.respx(base_url=base_url) - async def test_path_params_retrieve_pdf(self, async_client: AsyncMetronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - await async_client.v1.customers.invoices.with_raw_response.retrieve_pdf( - customer_id="", - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `invoice_id` but received ''"): - await async_client.v1.customers.invoices.with_raw_response.retrieve_pdf( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - invoice_id="", - ) diff --git a/tests/api_resources/v1/customers/test_named_schedules.py b/tests/api_resources/v1/customers/test_named_schedules.py deleted file mode 100644 index 8f0bbba9d..000000000 --- a/tests/api_resources/v1/customers/test_named_schedules.py +++ /dev/null @@ -1,215 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome._utils import parse_datetime -from metronome.types.v1.customers import ( - NamedScheduleRetrieveResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestNamedSchedules: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_retrieve(self, client: Metronome) -> None: - named_schedule = client.v1.customers.named_schedules.retrieve( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - ) - assert_matches_type(NamedScheduleRetrieveResponse, named_schedule, path=["response"]) - - @parametrize - def test_method_retrieve_with_all_params(self, client: Metronome) -> None: - named_schedule = client.v1.customers.named_schedules.retrieve( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - covering_date=parse_datetime("2022-02-15T00:00:00Z"), - ) - assert_matches_type(NamedScheduleRetrieveResponse, named_schedule, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Metronome) -> None: - response = client.v1.customers.named_schedules.with_raw_response.retrieve( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - named_schedule = response.parse() - assert_matches_type(NamedScheduleRetrieveResponse, named_schedule, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Metronome) -> None: - with client.v1.customers.named_schedules.with_streaming_response.retrieve( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - named_schedule = response.parse() - assert_matches_type(NamedScheduleRetrieveResponse, named_schedule, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_update(self, client: Metronome) -> None: - named_schedule = client.v1.customers.named_schedules.update( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - starting_at=parse_datetime("2022-02-01T00:00:00Z"), - value={"my_key": "my_value"}, - ) - assert named_schedule is None - - @parametrize - def test_method_update_with_all_params(self, client: Metronome) -> None: - named_schedule = client.v1.customers.named_schedules.update( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - starting_at=parse_datetime("2022-02-01T00:00:00Z"), - value={"my_key": "my_value"}, - ending_before=parse_datetime("2022-02-15T00:00:00Z"), - ) - assert named_schedule is None - - @parametrize - def test_raw_response_update(self, client: Metronome) -> None: - response = client.v1.customers.named_schedules.with_raw_response.update( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - starting_at=parse_datetime("2022-02-01T00:00:00Z"), - value={"my_key": "my_value"}, - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - named_schedule = response.parse() - assert named_schedule is None - - @parametrize - def test_streaming_response_update(self, client: Metronome) -> None: - with client.v1.customers.named_schedules.with_streaming_response.update( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - starting_at=parse_datetime("2022-02-01T00:00:00Z"), - value={"my_key": "my_value"}, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - named_schedule = response.parse() - assert named_schedule is None - - assert cast(Any, response.is_closed) is True - - -class TestAsyncNamedSchedules: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_retrieve(self, async_client: AsyncMetronome) -> None: - named_schedule = await async_client.v1.customers.named_schedules.retrieve( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - ) - assert_matches_type(NamedScheduleRetrieveResponse, named_schedule, path=["response"]) - - @parametrize - async def test_method_retrieve_with_all_params(self, async_client: AsyncMetronome) -> None: - named_schedule = await async_client.v1.customers.named_schedules.retrieve( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - covering_date=parse_datetime("2022-02-15T00:00:00Z"), - ) - assert_matches_type(NamedScheduleRetrieveResponse, named_schedule, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.named_schedules.with_raw_response.retrieve( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - named_schedule = await response.parse() - assert_matches_type(NamedScheduleRetrieveResponse, named_schedule, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.named_schedules.with_streaming_response.retrieve( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - named_schedule = await response.parse() - assert_matches_type(NamedScheduleRetrieveResponse, named_schedule, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_update(self, async_client: AsyncMetronome) -> None: - named_schedule = await async_client.v1.customers.named_schedules.update( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - starting_at=parse_datetime("2022-02-01T00:00:00Z"), - value={"my_key": "my_value"}, - ) - assert named_schedule is None - - @parametrize - async def test_method_update_with_all_params(self, async_client: AsyncMetronome) -> None: - named_schedule = await async_client.v1.customers.named_schedules.update( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - starting_at=parse_datetime("2022-02-01T00:00:00Z"), - value={"my_key": "my_value"}, - ending_before=parse_datetime("2022-02-15T00:00:00Z"), - ) - assert named_schedule is None - - @parametrize - async def test_raw_response_update(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.named_schedules.with_raw_response.update( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - starting_at=parse_datetime("2022-02-01T00:00:00Z"), - value={"my_key": "my_value"}, - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - named_schedule = await response.parse() - assert named_schedule is None - - @parametrize - async def test_streaming_response_update(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.named_schedules.with_streaming_response.update( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - schedule_name="my-schedule", - starting_at=parse_datetime("2022-02-01T00:00:00Z"), - value={"my_key": "my_value"}, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - named_schedule = await response.parse() - assert named_schedule is None - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v1/customers/test_plans.py b/tests/api_resources/v1/customers/test_plans.py deleted file mode 100644 index 670c8fbf2..000000000 --- a/tests/api_resources/v1/customers/test_plans.py +++ /dev/null @@ -1,521 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome._utils import parse_datetime -from metronome.pagination import SyncCursorPage, AsyncCursorPage -from metronome.types.v1.customers import ( - PlanAddResponse, - PlanEndResponse, - PlanListResponse, - PlanListPriceAdjustmentsResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestPlans: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_list(self, client: Metronome) -> None: - plan = client.v1.customers.plans.list( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(SyncCursorPage[PlanListResponse], plan, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Metronome) -> None: - plan = client.v1.customers.plans.list( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - limit=1, - next_page="next_page", - ) - assert_matches_type(SyncCursorPage[PlanListResponse], plan, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Metronome) -> None: - response = client.v1.customers.plans.with_raw_response.list( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - plan = response.parse() - assert_matches_type(SyncCursorPage[PlanListResponse], plan, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Metronome) -> None: - with client.v1.customers.plans.with_streaming_response.list( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - plan = response.parse() - assert_matches_type(SyncCursorPage[PlanListResponse], plan, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_list(self, client: Metronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - client.v1.customers.plans.with_raw_response.list( - customer_id="", - ) - - @parametrize - def test_method_add(self, client: Metronome) -> None: - plan = client.v1.customers.plans.add( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - plan_id="d2c06dae-9549-4d7d-bc04-b78dd3d241b8", - starting_on=parse_datetime("2021-02-01T00:00:00Z"), - ) - assert_matches_type(PlanAddResponse, plan, path=["response"]) - - @parametrize - def test_method_add_with_all_params(self, client: Metronome) -> None: - plan = client.v1.customers.plans.add( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - plan_id="d2c06dae-9549-4d7d-bc04-b78dd3d241b8", - starting_on=parse_datetime("2021-02-01T00:00:00Z"), - ending_before=parse_datetime("2022-02-01T00:00:00Z"), - net_payment_terms_days=0, - overage_rate_adjustments=[ - { - "custom_credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "fiat_currency_credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "to_fiat_conversion_factor": 0, - } - ], - price_adjustments=[ - { - "adjustment_type": "percentage", - "charge_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "start_period": 0, - "quantity": 0, - "tier": 0, - "value": 0, - } - ], - trial_spec={ - "length_in_days": 0, - "spending_cap": { - "amount": 0, - "credit_type_id": "credit_type_id", - }, - }, - ) - assert_matches_type(PlanAddResponse, plan, path=["response"]) - - @parametrize - def test_raw_response_add(self, client: Metronome) -> None: - response = client.v1.customers.plans.with_raw_response.add( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - plan_id="d2c06dae-9549-4d7d-bc04-b78dd3d241b8", - starting_on=parse_datetime("2021-02-01T00:00:00Z"), - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - plan = response.parse() - assert_matches_type(PlanAddResponse, plan, path=["response"]) - - @parametrize - def test_streaming_response_add(self, client: Metronome) -> None: - with client.v1.customers.plans.with_streaming_response.add( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - plan_id="d2c06dae-9549-4d7d-bc04-b78dd3d241b8", - starting_on=parse_datetime("2021-02-01T00:00:00Z"), - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - plan = response.parse() - assert_matches_type(PlanAddResponse, plan, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_add(self, client: Metronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - client.v1.customers.plans.with_raw_response.add( - customer_id="", - plan_id="d2c06dae-9549-4d7d-bc04-b78dd3d241b8", - starting_on=parse_datetime("2021-02-01T00:00:00Z"), - ) - - @parametrize - def test_method_end(self, client: Metronome) -> None: - plan = client.v1.customers.plans.end( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", - ) - assert_matches_type(PlanEndResponse, plan, path=["response"]) - - @parametrize - def test_method_end_with_all_params(self, client: Metronome) -> None: - plan = client.v1.customers.plans.end( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", - ending_before=parse_datetime("2021-02-01T00:00:00Z"), - void_invoices=True, - void_stripe_invoices=True, - ) - assert_matches_type(PlanEndResponse, plan, path=["response"]) - - @parametrize - def test_raw_response_end(self, client: Metronome) -> None: - response = client.v1.customers.plans.with_raw_response.end( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - plan = response.parse() - assert_matches_type(PlanEndResponse, plan, path=["response"]) - - @parametrize - def test_streaming_response_end(self, client: Metronome) -> None: - with client.v1.customers.plans.with_streaming_response.end( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - plan = response.parse() - assert_matches_type(PlanEndResponse, plan, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_end(self, client: Metronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - client.v1.customers.plans.with_raw_response.end( - customer_id="", - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_plan_id` but received ''"): - client.v1.customers.plans.with_raw_response.end( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_plan_id="", - ) - - @parametrize - def test_method_list_price_adjustments(self, client: Metronome) -> None: - plan = client.v1.customers.plans.list_price_adjustments( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", - ) - assert_matches_type(SyncCursorPage[PlanListPriceAdjustmentsResponse], plan, path=["response"]) - - @parametrize - def test_method_list_price_adjustments_with_all_params(self, client: Metronome) -> None: - plan = client.v1.customers.plans.list_price_adjustments( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", - limit=1, - next_page="next_page", - ) - assert_matches_type(SyncCursorPage[PlanListPriceAdjustmentsResponse], plan, path=["response"]) - - @parametrize - def test_raw_response_list_price_adjustments(self, client: Metronome) -> None: - response = client.v1.customers.plans.with_raw_response.list_price_adjustments( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - plan = response.parse() - assert_matches_type(SyncCursorPage[PlanListPriceAdjustmentsResponse], plan, path=["response"]) - - @parametrize - def test_streaming_response_list_price_adjustments(self, client: Metronome) -> None: - with client.v1.customers.plans.with_streaming_response.list_price_adjustments( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - plan = response.parse() - assert_matches_type(SyncCursorPage[PlanListPriceAdjustmentsResponse], plan, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_list_price_adjustments(self, client: Metronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - client.v1.customers.plans.with_raw_response.list_price_adjustments( - customer_id="", - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_plan_id` but received ''"): - client.v1.customers.plans.with_raw_response.list_price_adjustments( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_plan_id="", - ) - - -class TestAsyncPlans: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_list(self, async_client: AsyncMetronome) -> None: - plan = await async_client.v1.customers.plans.list( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(AsyncCursorPage[PlanListResponse], plan, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncMetronome) -> None: - plan = await async_client.v1.customers.plans.list( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - limit=1, - next_page="next_page", - ) - assert_matches_type(AsyncCursorPage[PlanListResponse], plan, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.plans.with_raw_response.list( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - plan = await response.parse() - assert_matches_type(AsyncCursorPage[PlanListResponse], plan, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.plans.with_streaming_response.list( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - plan = await response.parse() - assert_matches_type(AsyncCursorPage[PlanListResponse], plan, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_list(self, async_client: AsyncMetronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - await async_client.v1.customers.plans.with_raw_response.list( - customer_id="", - ) - - @parametrize - async def test_method_add(self, async_client: AsyncMetronome) -> None: - plan = await async_client.v1.customers.plans.add( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - plan_id="d2c06dae-9549-4d7d-bc04-b78dd3d241b8", - starting_on=parse_datetime("2021-02-01T00:00:00Z"), - ) - assert_matches_type(PlanAddResponse, plan, path=["response"]) - - @parametrize - async def test_method_add_with_all_params(self, async_client: AsyncMetronome) -> None: - plan = await async_client.v1.customers.plans.add( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - plan_id="d2c06dae-9549-4d7d-bc04-b78dd3d241b8", - starting_on=parse_datetime("2021-02-01T00:00:00Z"), - ending_before=parse_datetime("2022-02-01T00:00:00Z"), - net_payment_terms_days=0, - overage_rate_adjustments=[ - { - "custom_credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "fiat_currency_credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "to_fiat_conversion_factor": 0, - } - ], - price_adjustments=[ - { - "adjustment_type": "percentage", - "charge_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "start_period": 0, - "quantity": 0, - "tier": 0, - "value": 0, - } - ], - trial_spec={ - "length_in_days": 0, - "spending_cap": { - "amount": 0, - "credit_type_id": "credit_type_id", - }, - }, - ) - assert_matches_type(PlanAddResponse, plan, path=["response"]) - - @parametrize - async def test_raw_response_add(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.plans.with_raw_response.add( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - plan_id="d2c06dae-9549-4d7d-bc04-b78dd3d241b8", - starting_on=parse_datetime("2021-02-01T00:00:00Z"), - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - plan = await response.parse() - assert_matches_type(PlanAddResponse, plan, path=["response"]) - - @parametrize - async def test_streaming_response_add(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.plans.with_streaming_response.add( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - plan_id="d2c06dae-9549-4d7d-bc04-b78dd3d241b8", - starting_on=parse_datetime("2021-02-01T00:00:00Z"), - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - plan = await response.parse() - assert_matches_type(PlanAddResponse, plan, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_add(self, async_client: AsyncMetronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - await async_client.v1.customers.plans.with_raw_response.add( - customer_id="", - plan_id="d2c06dae-9549-4d7d-bc04-b78dd3d241b8", - starting_on=parse_datetime("2021-02-01T00:00:00Z"), - ) - - @parametrize - async def test_method_end(self, async_client: AsyncMetronome) -> None: - plan = await async_client.v1.customers.plans.end( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", - ) - assert_matches_type(PlanEndResponse, plan, path=["response"]) - - @parametrize - async def test_method_end_with_all_params(self, async_client: AsyncMetronome) -> None: - plan = await async_client.v1.customers.plans.end( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", - ending_before=parse_datetime("2021-02-01T00:00:00Z"), - void_invoices=True, - void_stripe_invoices=True, - ) - assert_matches_type(PlanEndResponse, plan, path=["response"]) - - @parametrize - async def test_raw_response_end(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.plans.with_raw_response.end( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - plan = await response.parse() - assert_matches_type(PlanEndResponse, plan, path=["response"]) - - @parametrize - async def test_streaming_response_end(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.plans.with_streaming_response.end( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - plan = await response.parse() - assert_matches_type(PlanEndResponse, plan, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_end(self, async_client: AsyncMetronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - await async_client.v1.customers.plans.with_raw_response.end( - customer_id="", - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_plan_id` but received ''"): - await async_client.v1.customers.plans.with_raw_response.end( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_plan_id="", - ) - - @parametrize - async def test_method_list_price_adjustments(self, async_client: AsyncMetronome) -> None: - plan = await async_client.v1.customers.plans.list_price_adjustments( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", - ) - assert_matches_type(AsyncCursorPage[PlanListPriceAdjustmentsResponse], plan, path=["response"]) - - @parametrize - async def test_method_list_price_adjustments_with_all_params(self, async_client: AsyncMetronome) -> None: - plan = await async_client.v1.customers.plans.list_price_adjustments( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", - limit=1, - next_page="next_page", - ) - assert_matches_type(AsyncCursorPage[PlanListPriceAdjustmentsResponse], plan, path=["response"]) - - @parametrize - async def test_raw_response_list_price_adjustments(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.plans.with_raw_response.list_price_adjustments( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - plan = await response.parse() - assert_matches_type(AsyncCursorPage[PlanListPriceAdjustmentsResponse], plan, path=["response"]) - - @parametrize - async def test_streaming_response_list_price_adjustments(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.plans.with_streaming_response.list_price_adjustments( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - plan = await response.parse() - assert_matches_type(AsyncCursorPage[PlanListPriceAdjustmentsResponse], plan, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_list_price_adjustments(self, async_client: AsyncMetronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - await async_client.v1.customers.plans.with_raw_response.list_price_adjustments( - customer_id="", - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", - ) - - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_plan_id` but received ''"): - await async_client.v1.customers.plans.with_raw_response.list_price_adjustments( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_plan_id="", - ) diff --git a/tests/api_resources/v1/settings/__init__.py b/tests/api_resources/v1/settings/__init__.py deleted file mode 100644 index fd8019a9a..000000000 --- a/tests/api_resources/v1/settings/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/v1/settings/test_billing_providers.py b/tests/api_resources/v1/settings/test_billing_providers.py deleted file mode 100644 index 75ad252cf..000000000 --- a/tests/api_resources/v1/settings/test_billing_providers.py +++ /dev/null @@ -1,183 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome.types.v1.settings import ( - BillingProviderListResponse, - BillingProviderCreateResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestBillingProviders: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Metronome) -> None: - billing_provider = client.v1.settings.billing_providers.create( - billing_provider="aws_marketplace", - configuration={ - "aws_external_id": "bar", - "aws_iam_role_arn": "bar", - }, - delivery_method="direct_to_billing_provider", - ) - assert_matches_type(BillingProviderCreateResponse, billing_provider, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Metronome) -> None: - response = client.v1.settings.billing_providers.with_raw_response.create( - billing_provider="aws_marketplace", - configuration={ - "aws_external_id": "bar", - "aws_iam_role_arn": "bar", - }, - delivery_method="direct_to_billing_provider", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - billing_provider = response.parse() - assert_matches_type(BillingProviderCreateResponse, billing_provider, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Metronome) -> None: - with client.v1.settings.billing_providers.with_streaming_response.create( - billing_provider="aws_marketplace", - configuration={ - "aws_external_id": "bar", - "aws_iam_role_arn": "bar", - }, - delivery_method="direct_to_billing_provider", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - billing_provider = response.parse() - assert_matches_type(BillingProviderCreateResponse, billing_provider, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_list(self, client: Metronome) -> None: - billing_provider = client.v1.settings.billing_providers.list() - assert_matches_type(BillingProviderListResponse, billing_provider, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Metronome) -> None: - billing_provider = client.v1.settings.billing_providers.list( - next_page="af26878a-de62-4a0d-9b77-3936f7c2b6d6", - ) - assert_matches_type(BillingProviderListResponse, billing_provider, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Metronome) -> None: - response = client.v1.settings.billing_providers.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - billing_provider = response.parse() - assert_matches_type(BillingProviderListResponse, billing_provider, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Metronome) -> None: - with client.v1.settings.billing_providers.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - billing_provider = response.parse() - assert_matches_type(BillingProviderListResponse, billing_provider, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncBillingProviders: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncMetronome) -> None: - billing_provider = await async_client.v1.settings.billing_providers.create( - billing_provider="aws_marketplace", - configuration={ - "aws_external_id": "bar", - "aws_iam_role_arn": "bar", - }, - delivery_method="direct_to_billing_provider", - ) - assert_matches_type(BillingProviderCreateResponse, billing_provider, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.settings.billing_providers.with_raw_response.create( - billing_provider="aws_marketplace", - configuration={ - "aws_external_id": "bar", - "aws_iam_role_arn": "bar", - }, - delivery_method="direct_to_billing_provider", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - billing_provider = await response.parse() - assert_matches_type(BillingProviderCreateResponse, billing_provider, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.settings.billing_providers.with_streaming_response.create( - billing_provider="aws_marketplace", - configuration={ - "aws_external_id": "bar", - "aws_iam_role_arn": "bar", - }, - delivery_method="direct_to_billing_provider", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - billing_provider = await response.parse() - assert_matches_type(BillingProviderCreateResponse, billing_provider, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_list(self, async_client: AsyncMetronome) -> None: - billing_provider = await async_client.v1.settings.billing_providers.list() - assert_matches_type(BillingProviderListResponse, billing_provider, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncMetronome) -> None: - billing_provider = await async_client.v1.settings.billing_providers.list( - next_page="af26878a-de62-4a0d-9b77-3936f7c2b6d6", - ) - assert_matches_type(BillingProviderListResponse, billing_provider, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.settings.billing_providers.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - billing_provider = await response.parse() - assert_matches_type(BillingProviderListResponse, billing_provider, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.settings.billing_providers.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - billing_provider = await response.parse() - assert_matches_type(BillingProviderListResponse, billing_provider, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v1/test_alerts.py b/tests/api_resources/v1/test_alerts.py deleted file mode 100644 index 603990b72..000000000 --- a/tests/api_resources/v1/test_alerts.py +++ /dev/null @@ -1,244 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome.types.v1 import AlertCreateResponse, AlertArchiveResponse - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestAlerts: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Metronome) -> None: - alert = client.v1.alerts.create( - alert_type="spend_threshold_reached", - name="$100 spend threshold reached", - threshold=10000, - ) - assert_matches_type(AlertCreateResponse, alert, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Metronome) -> None: - alert = client.v1.alerts.create( - alert_type="spend_threshold_reached", - name="$100 spend threshold reached", - threshold=10000, - billable_metric_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - credit_grant_type_filters=["enterprise"], - credit_type_id="2714e483-4ff1-48e4-9e25-ac732e8f24f2", - custom_field_filters=[ - { - "entity": "Contract", - "key": "key", - "value": "value", - } - ], - customer_id="4db51251-61de-4bfe-b9ce-495e244f3491", - evaluate_on_create=True, - group_values=[ - { - "key": "key", - "value": "value", - } - ], - invoice_types_filter=["SCHEDULED or USAGE"], - plan_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - seat_filter={ - "seat_group_key": "seat_group_key", - "seat_group_value": "seat_group_value", - }, - uniqueness_key="x", - ) - assert_matches_type(AlertCreateResponse, alert, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Metronome) -> None: - response = client.v1.alerts.with_raw_response.create( - alert_type="spend_threshold_reached", - name="$100 spend threshold reached", - threshold=10000, - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - alert = response.parse() - assert_matches_type(AlertCreateResponse, alert, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Metronome) -> None: - with client.v1.alerts.with_streaming_response.create( - alert_type="spend_threshold_reached", - name="$100 spend threshold reached", - threshold=10000, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - alert = response.parse() - assert_matches_type(AlertCreateResponse, alert, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_archive(self, client: Metronome) -> None: - alert = client.v1.alerts.archive( - id="8deed800-1b7a-495d-a207-6c52bac54dc9", - ) - assert_matches_type(AlertArchiveResponse, alert, path=["response"]) - - @parametrize - def test_method_archive_with_all_params(self, client: Metronome) -> None: - alert = client.v1.alerts.archive( - id="8deed800-1b7a-495d-a207-6c52bac54dc9", - release_uniqueness_key=True, - ) - assert_matches_type(AlertArchiveResponse, alert, path=["response"]) - - @parametrize - def test_raw_response_archive(self, client: Metronome) -> None: - response = client.v1.alerts.with_raw_response.archive( - id="8deed800-1b7a-495d-a207-6c52bac54dc9", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - alert = response.parse() - assert_matches_type(AlertArchiveResponse, alert, path=["response"]) - - @parametrize - def test_streaming_response_archive(self, client: Metronome) -> None: - with client.v1.alerts.with_streaming_response.archive( - id="8deed800-1b7a-495d-a207-6c52bac54dc9", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - alert = response.parse() - assert_matches_type(AlertArchiveResponse, alert, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncAlerts: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncMetronome) -> None: - alert = await async_client.v1.alerts.create( - alert_type="spend_threshold_reached", - name="$100 spend threshold reached", - threshold=10000, - ) - assert_matches_type(AlertCreateResponse, alert, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncMetronome) -> None: - alert = await async_client.v1.alerts.create( - alert_type="spend_threshold_reached", - name="$100 spend threshold reached", - threshold=10000, - billable_metric_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - credit_grant_type_filters=["enterprise"], - credit_type_id="2714e483-4ff1-48e4-9e25-ac732e8f24f2", - custom_field_filters=[ - { - "entity": "Contract", - "key": "key", - "value": "value", - } - ], - customer_id="4db51251-61de-4bfe-b9ce-495e244f3491", - evaluate_on_create=True, - group_values=[ - { - "key": "key", - "value": "value", - } - ], - invoice_types_filter=["SCHEDULED or USAGE"], - plan_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - seat_filter={ - "seat_group_key": "seat_group_key", - "seat_group_value": "seat_group_value", - }, - uniqueness_key="x", - ) - assert_matches_type(AlertCreateResponse, alert, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.alerts.with_raw_response.create( - alert_type="spend_threshold_reached", - name="$100 spend threshold reached", - threshold=10000, - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - alert = await response.parse() - assert_matches_type(AlertCreateResponse, alert, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.alerts.with_streaming_response.create( - alert_type="spend_threshold_reached", - name="$100 spend threshold reached", - threshold=10000, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - alert = await response.parse() - assert_matches_type(AlertCreateResponse, alert, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_archive(self, async_client: AsyncMetronome) -> None: - alert = await async_client.v1.alerts.archive( - id="8deed800-1b7a-495d-a207-6c52bac54dc9", - ) - assert_matches_type(AlertArchiveResponse, alert, path=["response"]) - - @parametrize - async def test_method_archive_with_all_params(self, async_client: AsyncMetronome) -> None: - alert = await async_client.v1.alerts.archive( - id="8deed800-1b7a-495d-a207-6c52bac54dc9", - release_uniqueness_key=True, - ) - assert_matches_type(AlertArchiveResponse, alert, path=["response"]) - - @parametrize - async def test_raw_response_archive(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.alerts.with_raw_response.archive( - id="8deed800-1b7a-495d-a207-6c52bac54dc9", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - alert = await response.parse() - assert_matches_type(AlertArchiveResponse, alert, path=["response"]) - - @parametrize - async def test_streaming_response_archive(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.alerts.with_streaming_response.archive( - id="8deed800-1b7a-495d-a207-6c52bac54dc9", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - alert = await response.parse() - assert_matches_type(AlertArchiveResponse, alert, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v1/test_audit_logs.py b/tests/api_resources/v1/test_audit_logs.py deleted file mode 100644 index 2dc559930..000000000 --- a/tests/api_resources/v1/test_audit_logs.py +++ /dev/null @@ -1,102 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome._utils import parse_datetime -from metronome.types.v1 import AuditLogListResponse -from metronome.pagination import SyncCursorPage, AsyncCursorPage - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestAuditLogs: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_list(self, client: Metronome) -> None: - audit_log = client.v1.audit_logs.list() - assert_matches_type(SyncCursorPage[AuditLogListResponse], audit_log, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Metronome) -> None: - audit_log = client.v1.audit_logs.list( - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - limit=1, - next_page="next_page", - resource_id="resource_id", - resource_type="resource_type", - sort="date_asc", - starting_on=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(SyncCursorPage[AuditLogListResponse], audit_log, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Metronome) -> None: - response = client.v1.audit_logs.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - audit_log = response.parse() - assert_matches_type(SyncCursorPage[AuditLogListResponse], audit_log, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Metronome) -> None: - with client.v1.audit_logs.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - audit_log = response.parse() - assert_matches_type(SyncCursorPage[AuditLogListResponse], audit_log, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncAuditLogs: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_list(self, async_client: AsyncMetronome) -> None: - audit_log = await async_client.v1.audit_logs.list() - assert_matches_type(AsyncCursorPage[AuditLogListResponse], audit_log, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncMetronome) -> None: - audit_log = await async_client.v1.audit_logs.list( - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - limit=1, - next_page="next_page", - resource_id="resource_id", - resource_type="resource_type", - sort="date_asc", - starting_on=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(AsyncCursorPage[AuditLogListResponse], audit_log, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.audit_logs.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - audit_log = await response.parse() - assert_matches_type(AsyncCursorPage[AuditLogListResponse], audit_log, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.audit_logs.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - audit_log = await response.parse() - assert_matches_type(AsyncCursorPage[AuditLogListResponse], audit_log, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v1/test_billable_metrics.py b/tests/api_resources/v1/test_billable_metrics.py deleted file mode 100644 index be5732977..000000000 --- a/tests/api_resources/v1/test_billable_metrics.py +++ /dev/null @@ -1,370 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome.types.v1 import ( - BillableMetricListResponse, - BillableMetricCreateResponse, - BillableMetricArchiveResponse, - BillableMetricRetrieveResponse, -) -from metronome.pagination import SyncCursorPage, AsyncCursorPage - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestBillableMetrics: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Metronome) -> None: - billable_metric = client.v1.billable_metrics.create( - name="CPU Hours", - ) - assert_matches_type(BillableMetricCreateResponse, billable_metric, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Metronome) -> None: - billable_metric = client.v1.billable_metrics.create( - name="CPU Hours", - aggregation_key="cpu_hours", - aggregation_type="SUM", - custom_fields={"foo": "string"}, - event_type_filter={ - "in_values": ["cpu_usage"], - "not_in_values": ["string"], - }, - group_keys=[["region"], ["machine_type"]], - property_filters=[ - { - "name": "cpu_hours", - "exists": True, - "in_values": ["string"], - "not_in_values": ["string"], - }, - { - "name": "region", - "exists": True, - "in_values": ["EU", "NA"], - "not_in_values": ["string"], - }, - { - "name": "machine_type", - "exists": True, - "in_values": ["slow", "fast"], - "not_in_values": ["string"], - }, - ], - sql="sql", - ) - assert_matches_type(BillableMetricCreateResponse, billable_metric, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Metronome) -> None: - response = client.v1.billable_metrics.with_raw_response.create( - name="CPU Hours", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - billable_metric = response.parse() - assert_matches_type(BillableMetricCreateResponse, billable_metric, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Metronome) -> None: - with client.v1.billable_metrics.with_streaming_response.create( - name="CPU Hours", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - billable_metric = response.parse() - assert_matches_type(BillableMetricCreateResponse, billable_metric, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_retrieve(self, client: Metronome) -> None: - billable_metric = client.v1.billable_metrics.retrieve( - billable_metric_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(BillableMetricRetrieveResponse, billable_metric, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Metronome) -> None: - response = client.v1.billable_metrics.with_raw_response.retrieve( - billable_metric_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - billable_metric = response.parse() - assert_matches_type(BillableMetricRetrieveResponse, billable_metric, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Metronome) -> None: - with client.v1.billable_metrics.with_streaming_response.retrieve( - billable_metric_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - billable_metric = response.parse() - assert_matches_type(BillableMetricRetrieveResponse, billable_metric, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_retrieve(self, client: Metronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `billable_metric_id` but received ''"): - client.v1.billable_metrics.with_raw_response.retrieve( - billable_metric_id="", - ) - - @parametrize - def test_method_list(self, client: Metronome) -> None: - billable_metric = client.v1.billable_metrics.list() - assert_matches_type(SyncCursorPage[BillableMetricListResponse], billable_metric, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Metronome) -> None: - billable_metric = client.v1.billable_metrics.list( - include_archived=True, - limit=1, - next_page="next_page", - ) - assert_matches_type(SyncCursorPage[BillableMetricListResponse], billable_metric, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Metronome) -> None: - response = client.v1.billable_metrics.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - billable_metric = response.parse() - assert_matches_type(SyncCursorPage[BillableMetricListResponse], billable_metric, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Metronome) -> None: - with client.v1.billable_metrics.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - billable_metric = response.parse() - assert_matches_type(SyncCursorPage[BillableMetricListResponse], billable_metric, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_archive(self, client: Metronome) -> None: - billable_metric = client.v1.billable_metrics.archive( - id="8deed800-1b7a-495d-a207-6c52bac54dc9", - ) - assert_matches_type(BillableMetricArchiveResponse, billable_metric, path=["response"]) - - @parametrize - def test_raw_response_archive(self, client: Metronome) -> None: - response = client.v1.billable_metrics.with_raw_response.archive( - id="8deed800-1b7a-495d-a207-6c52bac54dc9", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - billable_metric = response.parse() - assert_matches_type(BillableMetricArchiveResponse, billable_metric, path=["response"]) - - @parametrize - def test_streaming_response_archive(self, client: Metronome) -> None: - with client.v1.billable_metrics.with_streaming_response.archive( - id="8deed800-1b7a-495d-a207-6c52bac54dc9", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - billable_metric = response.parse() - assert_matches_type(BillableMetricArchiveResponse, billable_metric, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncBillableMetrics: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncMetronome) -> None: - billable_metric = await async_client.v1.billable_metrics.create( - name="CPU Hours", - ) - assert_matches_type(BillableMetricCreateResponse, billable_metric, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncMetronome) -> None: - billable_metric = await async_client.v1.billable_metrics.create( - name="CPU Hours", - aggregation_key="cpu_hours", - aggregation_type="SUM", - custom_fields={"foo": "string"}, - event_type_filter={ - "in_values": ["cpu_usage"], - "not_in_values": ["string"], - }, - group_keys=[["region"], ["machine_type"]], - property_filters=[ - { - "name": "cpu_hours", - "exists": True, - "in_values": ["string"], - "not_in_values": ["string"], - }, - { - "name": "region", - "exists": True, - "in_values": ["EU", "NA"], - "not_in_values": ["string"], - }, - { - "name": "machine_type", - "exists": True, - "in_values": ["slow", "fast"], - "not_in_values": ["string"], - }, - ], - sql="sql", - ) - assert_matches_type(BillableMetricCreateResponse, billable_metric, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.billable_metrics.with_raw_response.create( - name="CPU Hours", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - billable_metric = await response.parse() - assert_matches_type(BillableMetricCreateResponse, billable_metric, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.billable_metrics.with_streaming_response.create( - name="CPU Hours", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - billable_metric = await response.parse() - assert_matches_type(BillableMetricCreateResponse, billable_metric, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_retrieve(self, async_client: AsyncMetronome) -> None: - billable_metric = await async_client.v1.billable_metrics.retrieve( - billable_metric_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(BillableMetricRetrieveResponse, billable_metric, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.billable_metrics.with_raw_response.retrieve( - billable_metric_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - billable_metric = await response.parse() - assert_matches_type(BillableMetricRetrieveResponse, billable_metric, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.billable_metrics.with_streaming_response.retrieve( - billable_metric_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - billable_metric = await response.parse() - assert_matches_type(BillableMetricRetrieveResponse, billable_metric, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_retrieve(self, async_client: AsyncMetronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `billable_metric_id` but received ''"): - await async_client.v1.billable_metrics.with_raw_response.retrieve( - billable_metric_id="", - ) - - @parametrize - async def test_method_list(self, async_client: AsyncMetronome) -> None: - billable_metric = await async_client.v1.billable_metrics.list() - assert_matches_type(AsyncCursorPage[BillableMetricListResponse], billable_metric, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncMetronome) -> None: - billable_metric = await async_client.v1.billable_metrics.list( - include_archived=True, - limit=1, - next_page="next_page", - ) - assert_matches_type(AsyncCursorPage[BillableMetricListResponse], billable_metric, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.billable_metrics.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - billable_metric = await response.parse() - assert_matches_type(AsyncCursorPage[BillableMetricListResponse], billable_metric, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.billable_metrics.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - billable_metric = await response.parse() - assert_matches_type(AsyncCursorPage[BillableMetricListResponse], billable_metric, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_archive(self, async_client: AsyncMetronome) -> None: - billable_metric = await async_client.v1.billable_metrics.archive( - id="8deed800-1b7a-495d-a207-6c52bac54dc9", - ) - assert_matches_type(BillableMetricArchiveResponse, billable_metric, path=["response"]) - - @parametrize - async def test_raw_response_archive(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.billable_metrics.with_raw_response.archive( - id="8deed800-1b7a-495d-a207-6c52bac54dc9", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - billable_metric = await response.parse() - assert_matches_type(BillableMetricArchiveResponse, billable_metric, path=["response"]) - - @parametrize - async def test_streaming_response_archive(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.billable_metrics.with_streaming_response.archive( - id="8deed800-1b7a-495d-a207-6c52bac54dc9", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - billable_metric = await response.parse() - assert_matches_type(BillableMetricArchiveResponse, billable_metric, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v1/test_contracts.py b/tests/api_resources/v1/test_contracts.py deleted file mode 100644 index 71c08a409..000000000 --- a/tests/api_resources/v1/test_contracts.py +++ /dev/null @@ -1,2829 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome._utils import parse_datetime -from metronome.types.v1 import ( - ContractListResponse, - ContractAmendResponse, - ContractCreateResponse, - ContractArchiveResponse, - ContractRetrieveResponse, - ContractListBalancesResponse, - ContractGetNetBalanceResponse, - ContractUpdateEndDateResponse, - ContractRetrieveRateScheduleResponse, - ContractCreateHistoricalInvoicesResponse, - ContractScheduleProServicesInvoiceResponse, - ContractRetrieveSubscriptionQuantityHistoryResponse, -) -from metronome.pagination import SyncBodyCursorPage, AsyncBodyCursorPage - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestContracts: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Metronome) -> None: - contract = client.v1.contracts.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) - assert_matches_type(ContractCreateResponse, contract, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Metronome) -> None: - contract = client.v1.contracts.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - billing_provider_configuration={ - "billing_provider": "stripe", - "billing_provider_configuration_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "delivery_method": "direct_to_billing_provider", - }, - commits=[ - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "type": "PREPAID", - "access_schedule": { - "schedule_items": [ - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "amount": 0, - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "hierarchy_configuration": {"child_access": {"type": "ALL"}}, - "invoice_schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "do_not_invoice": True, - "recurring_schedule": { - "amount_distribution": "DIVIDED", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "frequency": "MONTHLY", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - "schedule_items": [ - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - } - ], - }, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "payment_gate_config": { - "payment_gate_type": "NONE", - "precalculated_tax_config": { - "tax_amount": 0, - "tax_name": "tax_name", - }, - "stripe_config": { - "payment_type": "INVOICE", - "invoice_metadata": {"foo": "string"}, - "on_session_payment": True, - }, - "tax_type": "NONE", - }, - "priority": 0, - "rate_type": "COMMIT_RATE", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - "temporary_id": "temporary_id", - } - ], - credits=[ - { - "access_schedule": { - "schedule_items": [ - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "hierarchy_configuration": {"child_access": {"type": "ALL"}}, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "priority": 0, - "rate_type": "COMMIT_RATE", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - } - ], - custom_fields={"foo": "string"}, - discounts=[ - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "do_not_invoice": True, - "recurring_schedule": { - "amount_distribution": "DIVIDED", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "frequency": "MONTHLY", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - "schedule_items": [ - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - } - ], - }, - "custom_fields": {"foo": "string"}, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - } - ], - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - hierarchy_configuration={ - "parent": { - "contract_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "customer_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "parent_behavior": {"invoice_consolidation_type": "CONCATENATE"}, - "payer": "SELF", - "usage_statement_behavior": "CONSOLIDATE", - }, - multiplier_override_prioritization="LOWEST_MULTIPLIER", - name="name", - net_payment_terms_days=0, - netsuite_sales_order_id="netsuite_sales_order_id", - overrides=[ - { - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "applicable_product_tags": ["string"], - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "entitled": True, - "is_commit_specific": True, - "multiplier": 0, - "override_specifiers": [ - { - "billing_frequency": "MONTHLY", - "commit_ids": ["string"], - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - "recurring_commit_ids": ["string"], - "recurring_credit_ids": ["string"], - } - ], - "overwrite_rate": { - "rate_type": "FLAT", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "custom_rate": {"foo": "bar"}, - "is_prorated": True, - "price": 0, - "quantity": 0, - "tiers": [ - { - "price": 0, - "size": 0, - } - ], - }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "target": "COMMIT_RATE", - "tiers": [ - { - "multiplier": 0, - "size": 0, - } - ], - "type": "OVERWRITE", - } - ], - package_alias="package_alias", - package_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - prepaid_balance_threshold_configuration={ - "commit": { - "product_id": "product_id", - "description": "description", - "name": "name", - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - }, - "is_enabled": True, - "payment_gate_config": { - "payment_gate_type": "NONE", - "precalculated_tax_config": { - "tax_amount": 0, - "tax_name": "tax_name", - }, - "stripe_config": { - "payment_type": "INVOICE", - "invoice_metadata": {"foo": "string"}, - }, - "tax_type": "NONE", - }, - "recharge_to_amount": 0, - "threshold_amount": 0, - "custom_credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - professional_services=[ - { - "max_amount": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "quantity": 0, - "unit_price": 0, - "custom_fields": {"foo": "string"}, - "description": "description", - "netsuite_sales_order_id": "netsuite_sales_order_id", - } - ], - rate_card_alias="rate_card_alias", - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - recurring_commits=[ - { - "access_amount": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "unit_price": 0, - "quantity": 0, - }, - "commit_duration": { - "value": 0, - "unit": "PERIODS", - }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "description": "description", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "hierarchy_configuration": {"child_access": {"type": "ALL"}}, - "invoice_amount": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "quantity": 0, - "unit_price": 0, - }, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "proration": "NONE", - "rate_type": "COMMIT_RATE", - "recurrence_frequency": "MONTHLY", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - "subscription_config": { - "apply_seat_increase_config": {"is_prorated": True}, - "subscription_id": "subscription_id", - "allocation": "INDIVIDUAL", - }, - "temporary_id": "temporary_id", - } - ], - recurring_credits=[ - { - "access_amount": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "unit_price": 0, - "quantity": 0, - }, - "commit_duration": { - "value": 0, - "unit": "PERIODS", - }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "description": "description", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "hierarchy_configuration": {"child_access": {"type": "ALL"}}, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "proration": "NONE", - "rate_type": "COMMIT_RATE", - "recurrence_frequency": "MONTHLY", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - "subscription_config": { - "apply_seat_increase_config": {"is_prorated": True}, - "subscription_id": "subscription_id", - "allocation": "INDIVIDUAL", - }, - "temporary_id": "temporary_id", - } - ], - reseller_royalties=[ - { - "fraction": 0, - "netsuite_reseller_id": "netsuite_reseller_id", - "reseller_type": "AWS", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "aws_options": { - "aws_account_number": "aws_account_number", - "aws_offer_id": "aws_offer_id", - "aws_payer_reference_id": "aws_payer_reference_id", - }, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "gcp_options": { - "gcp_account_id": "gcp_account_id", - "gcp_offer_id": "gcp_offer_id", - }, - "reseller_contract_value": 0, - } - ], - revenue_system_configuration={ - "delivery_method": "direct_to_billing_provider", - "provider": "netsuite", - "revenue_system_configuration_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - salesforce_opportunity_id="salesforce_opportunity_id", - scheduled_charges=[ - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "do_not_invoice": True, - "recurring_schedule": { - "amount_distribution": "DIVIDED", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "frequency": "MONTHLY", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - "schedule_items": [ - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - } - ], - }, - "custom_fields": {"foo": "string"}, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - } - ], - scheduled_charges_on_usage_invoices="ALL", - spend_threshold_configuration={ - "commit": { - "product_id": "product_id", - "description": "description", - "name": "name", - }, - "is_enabled": True, - "payment_gate_config": { - "payment_gate_type": "NONE", - "precalculated_tax_config": { - "tax_amount": 0, - "tax_name": "tax_name", - }, - "stripe_config": { - "payment_type": "INVOICE", - "invoice_metadata": {"foo": "string"}, - }, - "tax_type": "NONE", - }, - "threshold_amount": 0, - }, - subscriptions=[ - { - "collection_schedule": "ADVANCE", - "proration": { - "invoice_behavior": "BILL_IMMEDIATELY", - "is_prorated": True, - }, - "subscription_rate": { - "billing_frequency": "MONTHLY", - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "custom_fields": {"foo": "string"}, - "description": "description", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "initial_quantity": 0, - "name": "name", - "quantity_management_mode": "SEAT_BASED", - "seat_config": { - "initial_seat_ids": ["string"], - "seat_group_key": "seat_group_key", - "initial_unassigned_seats": 0, - }, - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "temporary_id": "temporary_id", - } - ], - total_contract_value=0, - transition={ - "from_contract_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "type": "SUPERSEDE", - "future_invoice_behavior": {"trueup": "REMOVE"}, - }, - uniqueness_key="x", - usage_filter={ - "group_key": "group_key", - "group_values": ["string"], - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - usage_statement_schedule={ - "frequency": "MONTHLY", - "billing_anchor_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "day": "FIRST_OF_MONTH", - "invoice_generation_starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - ) - assert_matches_type(ContractCreateResponse, contract, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Metronome) -> None: - response = client.v1.contracts.with_raw_response.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = response.parse() - assert_matches_type(ContractCreateResponse, contract, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Metronome) -> None: - with client.v1.contracts.with_streaming_response.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = response.parse() - assert_matches_type(ContractCreateResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_retrieve(self, client: Metronome) -> None: - contract = client.v1.contracts.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(ContractRetrieveResponse, contract, path=["response"]) - - @parametrize - def test_method_retrieve_with_all_params(self, client: Metronome) -> None: - contract = client.v1.contracts.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - include_balance=True, - include_ledgers=True, - ) - assert_matches_type(ContractRetrieveResponse, contract, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Metronome) -> None: - response = client.v1.contracts.with_raw_response.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = response.parse() - assert_matches_type(ContractRetrieveResponse, contract, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Metronome) -> None: - with client.v1.contracts.with_streaming_response.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = response.parse() - assert_matches_type(ContractRetrieveResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_list(self, client: Metronome) -> None: - contract = client.v1.contracts.list( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) - assert_matches_type(ContractListResponse, contract, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Metronome) -> None: - contract = client.v1.contracts.list( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - covering_date=parse_datetime("2019-12-27T18:11:19.117Z"), - include_archived=True, - include_balance=True, - include_ledgers=True, - starting_at=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(ContractListResponse, contract, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Metronome) -> None: - response = client.v1.contracts.with_raw_response.list( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = response.parse() - assert_matches_type(ContractListResponse, contract, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Metronome) -> None: - with client.v1.contracts.with_streaming_response.list( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = response.parse() - assert_matches_type(ContractListResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_add_manual_balance_entry(self, client: Metronome) -> None: - contract = client.v1.contracts.add_manual_balance_entry( - id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - amount=-1000, - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - reason="Reason for entry", - segment_id="66368e29-3f97-4d15-a6e9-120897f0070a", - ) - assert contract is None - - @parametrize - def test_method_add_manual_balance_entry_with_all_params(self, client: Metronome) -> None: - contract = client.v1.contracts.add_manual_balance_entry( - id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - amount=-1000, - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - reason="Reason for entry", - segment_id="66368e29-3f97-4d15-a6e9-120897f0070a", - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - per_group_amounts={"foo": 0}, - timestamp=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert contract is None - - @parametrize - def test_raw_response_add_manual_balance_entry(self, client: Metronome) -> None: - response = client.v1.contracts.with_raw_response.add_manual_balance_entry( - id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - amount=-1000, - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - reason="Reason for entry", - segment_id="66368e29-3f97-4d15-a6e9-120897f0070a", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = response.parse() - assert contract is None - - @parametrize - def test_streaming_response_add_manual_balance_entry(self, client: Metronome) -> None: - with client.v1.contracts.with_streaming_response.add_manual_balance_entry( - id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - amount=-1000, - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - reason="Reason for entry", - segment_id="66368e29-3f97-4d15-a6e9-120897f0070a", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = response.parse() - assert contract is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_amend(self, client: Metronome) -> None: - contract = client.v1.contracts.amend( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) - assert_matches_type(ContractAmendResponse, contract, path=["response"]) - - @parametrize - def test_method_amend_with_all_params(self, client: Metronome) -> None: - contract = client.v1.contracts.amend( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - commits=[ - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "type": "PREPAID", - "access_schedule": { - "schedule_items": [ - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "amount": 0, - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "hierarchy_configuration": {"child_access": {"type": "ALL"}}, - "invoice_schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "do_not_invoice": True, - "recurring_schedule": { - "amount_distribution": "DIVIDED", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "frequency": "MONTHLY", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - "schedule_items": [ - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - } - ], - }, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "payment_gate_config": { - "payment_gate_type": "NONE", - "precalculated_tax_config": { - "tax_amount": 0, - "tax_name": "tax_name", - }, - "stripe_config": { - "payment_type": "INVOICE", - "invoice_metadata": {"foo": "string"}, - "on_session_payment": True, - }, - "tax_type": "NONE", - }, - "priority": 0, - "rate_type": "COMMIT_RATE", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - "temporary_id": "temporary_id", - } - ], - credits=[ - { - "access_schedule": { - "schedule_items": [ - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "hierarchy_configuration": {"child_access": {"type": "ALL"}}, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "priority": 0, - "rate_type": "COMMIT_RATE", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - } - ], - custom_fields={"foo": "string"}, - discounts=[ - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "do_not_invoice": True, - "recurring_schedule": { - "amount_distribution": "DIVIDED", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "frequency": "MONTHLY", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - "schedule_items": [ - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - } - ], - }, - "custom_fields": {"foo": "string"}, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - } - ], - netsuite_sales_order_id="netsuite_sales_order_id", - overrides=[ - { - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "applicable_product_tags": ["string"], - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "entitled": True, - "is_commit_specific": True, - "multiplier": 0, - "override_specifiers": [ - { - "billing_frequency": "MONTHLY", - "commit_ids": ["string"], - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - "recurring_commit_ids": ["string"], - "recurring_credit_ids": ["string"], - } - ], - "overwrite_rate": { - "rate_type": "FLAT", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "custom_rate": {"foo": "bar"}, - "is_prorated": True, - "price": 0, - "quantity": 0, - "tiers": [ - { - "price": 0, - "size": 0, - } - ], - }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "target": "COMMIT_RATE", - "tiers": [ - { - "multiplier": 0, - "size": 0, - } - ], - "type": "OVERWRITE", - } - ], - professional_services=[ - { - "max_amount": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "quantity": 0, - "unit_price": 0, - "custom_fields": {"foo": "string"}, - "description": "description", - "netsuite_sales_order_id": "netsuite_sales_order_id", - } - ], - reseller_royalties=[ - { - "reseller_type": "AWS", - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "aws_options": { - "aws_account_number": "aws_account_number", - "aws_offer_id": "aws_offer_id", - "aws_payer_reference_id": "aws_payer_reference_id", - }, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "fraction": 0, - "gcp_options": { - "gcp_account_id": "gcp_account_id", - "gcp_offer_id": "gcp_offer_id", - }, - "netsuite_reseller_id": "netsuite_reseller_id", - "reseller_contract_value": 0, - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - salesforce_opportunity_id="salesforce_opportunity_id", - scheduled_charges=[ - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "do_not_invoice": True, - "recurring_schedule": { - "amount_distribution": "DIVIDED", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "frequency": "MONTHLY", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - "schedule_items": [ - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - } - ], - }, - "custom_fields": {"foo": "string"}, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - } - ], - total_contract_value=0, - ) - assert_matches_type(ContractAmendResponse, contract, path=["response"]) - - @parametrize - def test_raw_response_amend(self, client: Metronome) -> None: - response = client.v1.contracts.with_raw_response.amend( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = response.parse() - assert_matches_type(ContractAmendResponse, contract, path=["response"]) - - @parametrize - def test_streaming_response_amend(self, client: Metronome) -> None: - with client.v1.contracts.with_streaming_response.amend( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = response.parse() - assert_matches_type(ContractAmendResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_archive(self, client: Metronome) -> None: - contract = client.v1.contracts.archive( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - void_invoices=True, - ) - assert_matches_type(ContractArchiveResponse, contract, path=["response"]) - - @parametrize - def test_raw_response_archive(self, client: Metronome) -> None: - response = client.v1.contracts.with_raw_response.archive( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - void_invoices=True, - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = response.parse() - assert_matches_type(ContractArchiveResponse, contract, path=["response"]) - - @parametrize - def test_streaming_response_archive(self, client: Metronome) -> None: - with client.v1.contracts.with_streaming_response.archive( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - void_invoices=True, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = response.parse() - assert_matches_type(ContractArchiveResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_create_historical_invoices(self, client: Metronome) -> None: - contract = client.v1.contracts.create_historical_invoices( - invoices=[ - { - "contract_id": "d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - "credit_type_id": "2714e483-4ff1-48e4-9e25-ac732e8f24f2", - "customer_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", - "exclusive_end_date": parse_datetime("2020-02-01T00:00:00.000Z"), - "inclusive_start_date": parse_datetime("2020-01-01T00:00:00.000Z"), - "issue_date": parse_datetime("2020-02-01T00:00:00.000Z"), - "usage_line_items": [ - { - "exclusive_end_date": parse_datetime("2020-02-01T00:00:00.000Z"), - "inclusive_start_date": parse_datetime("2020-01-01T00:00:00.000Z"), - "product_id": "f14d6729-6a44-4b13-9908-9387f1918790", - } - ], - } - ], - preview=False, - ) - assert_matches_type(ContractCreateHistoricalInvoicesResponse, contract, path=["response"]) - - @parametrize - def test_raw_response_create_historical_invoices(self, client: Metronome) -> None: - response = client.v1.contracts.with_raw_response.create_historical_invoices( - invoices=[ - { - "contract_id": "d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - "credit_type_id": "2714e483-4ff1-48e4-9e25-ac732e8f24f2", - "customer_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", - "exclusive_end_date": parse_datetime("2020-02-01T00:00:00.000Z"), - "inclusive_start_date": parse_datetime("2020-01-01T00:00:00.000Z"), - "issue_date": parse_datetime("2020-02-01T00:00:00.000Z"), - "usage_line_items": [ - { - "exclusive_end_date": parse_datetime("2020-02-01T00:00:00.000Z"), - "inclusive_start_date": parse_datetime("2020-01-01T00:00:00.000Z"), - "product_id": "f14d6729-6a44-4b13-9908-9387f1918790", - } - ], - } - ], - preview=False, - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = response.parse() - assert_matches_type(ContractCreateHistoricalInvoicesResponse, contract, path=["response"]) - - @parametrize - def test_streaming_response_create_historical_invoices(self, client: Metronome) -> None: - with client.v1.contracts.with_streaming_response.create_historical_invoices( - invoices=[ - { - "contract_id": "d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - "credit_type_id": "2714e483-4ff1-48e4-9e25-ac732e8f24f2", - "customer_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", - "exclusive_end_date": parse_datetime("2020-02-01T00:00:00.000Z"), - "inclusive_start_date": parse_datetime("2020-01-01T00:00:00.000Z"), - "issue_date": parse_datetime("2020-02-01T00:00:00.000Z"), - "usage_line_items": [ - { - "exclusive_end_date": parse_datetime("2020-02-01T00:00:00.000Z"), - "inclusive_start_date": parse_datetime("2020-01-01T00:00:00.000Z"), - "product_id": "f14d6729-6a44-4b13-9908-9387f1918790", - } - ], - } - ], - preview=False, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = response.parse() - assert_matches_type(ContractCreateHistoricalInvoicesResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_get_net_balance(self, client: Metronome) -> None: - contract = client.v1.contracts.get_net_balance( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(ContractGetNetBalanceResponse, contract, path=["response"]) - - @parametrize - def test_method_get_net_balance_with_all_params(self, client: Metronome) -> None: - contract = client.v1.contracts.get_net_balance( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - credit_type_id="2714e483-4ff1-48e4-9e25-ac732e8f24f2", - filters=[ - { - "balance_types": ["CREDIT"], - "custom_fields": {"campaign": "free-trial"}, - "ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - }, - { - "balance_types": ["PREPAID_COMMIT", "POSTPAID_COMMIT"], - "custom_fields": {"campaign": "signup-promotion"}, - "ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - }, - ], - invoice_inclusion_mode="FINALIZED", - ) - assert_matches_type(ContractGetNetBalanceResponse, contract, path=["response"]) - - @parametrize - def test_raw_response_get_net_balance(self, client: Metronome) -> None: - response = client.v1.contracts.with_raw_response.get_net_balance( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = response.parse() - assert_matches_type(ContractGetNetBalanceResponse, contract, path=["response"]) - - @parametrize - def test_streaming_response_get_net_balance(self, client: Metronome) -> None: - with client.v1.contracts.with_streaming_response.get_net_balance( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = response.parse() - assert_matches_type(ContractGetNetBalanceResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_list_balances(self, client: Metronome) -> None: - contract = client.v1.contracts.list_balances( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(SyncBodyCursorPage[ContractListBalancesResponse], contract, path=["response"]) - - @parametrize - def test_method_list_balances_with_all_params(self, client: Metronome) -> None: - contract = client.v1.contracts.list_balances( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - covering_date=parse_datetime("2019-12-27T18:11:19.117Z"), - effective_before=parse_datetime("2019-12-27T18:11:19.117Z"), - exclude_zero_balances=True, - include_archived=True, - include_balance=True, - include_contract_balances=True, - include_ledgers=True, - limit=1, - next_page="next_page", - starting_at=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(SyncBodyCursorPage[ContractListBalancesResponse], contract, path=["response"]) - - @parametrize - def test_raw_response_list_balances(self, client: Metronome) -> None: - response = client.v1.contracts.with_raw_response.list_balances( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = response.parse() - assert_matches_type(SyncBodyCursorPage[ContractListBalancesResponse], contract, path=["response"]) - - @parametrize - def test_streaming_response_list_balances(self, client: Metronome) -> None: - with client.v1.contracts.with_streaming_response.list_balances( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = response.parse() - assert_matches_type(SyncBodyCursorPage[ContractListBalancesResponse], contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_retrieve_rate_schedule(self, client: Metronome) -> None: - contract = client.v1.contracts.retrieve_rate_schedule( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(ContractRetrieveRateScheduleResponse, contract, path=["response"]) - - @parametrize - def test_method_retrieve_rate_schedule_with_all_params(self, client: Metronome) -> None: - contract = client.v1.contracts.retrieve_rate_schedule( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - limit=1, - next_page="next_page", - at=parse_datetime("2020-01-01T00:00:00.000Z"), - selectors=[ - { - "billing_frequency": "MONTHLY", - "partial_pricing_group_values": { - "region": "us-west-2", - "cloud": "aws", - }, - "pricing_group_values": {"foo": "string"}, - "product_id": "d6300dbb-882e-4d2d-8dec-5125d16b65d0", - "product_tags": ["string"], - } - ], - ) - assert_matches_type(ContractRetrieveRateScheduleResponse, contract, path=["response"]) - - @parametrize - def test_raw_response_retrieve_rate_schedule(self, client: Metronome) -> None: - response = client.v1.contracts.with_raw_response.retrieve_rate_schedule( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = response.parse() - assert_matches_type(ContractRetrieveRateScheduleResponse, contract, path=["response"]) - - @parametrize - def test_streaming_response_retrieve_rate_schedule(self, client: Metronome) -> None: - with client.v1.contracts.with_streaming_response.retrieve_rate_schedule( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = response.parse() - assert_matches_type(ContractRetrieveRateScheduleResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_retrieve_subscription_quantity_history(self, client: Metronome) -> None: - contract = client.v1.contracts.retrieve_subscription_quantity_history( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - subscription_id="1a824d53-bde6-4d82-96d7-6347ff227d5c", - ) - assert_matches_type(ContractRetrieveSubscriptionQuantityHistoryResponse, contract, path=["response"]) - - @parametrize - def test_raw_response_retrieve_subscription_quantity_history(self, client: Metronome) -> None: - response = client.v1.contracts.with_raw_response.retrieve_subscription_quantity_history( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - subscription_id="1a824d53-bde6-4d82-96d7-6347ff227d5c", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = response.parse() - assert_matches_type(ContractRetrieveSubscriptionQuantityHistoryResponse, contract, path=["response"]) - - @parametrize - def test_streaming_response_retrieve_subscription_quantity_history(self, client: Metronome) -> None: - with client.v1.contracts.with_streaming_response.retrieve_subscription_quantity_history( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - subscription_id="1a824d53-bde6-4d82-96d7-6347ff227d5c", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = response.parse() - assert_matches_type(ContractRetrieveSubscriptionQuantityHistoryResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_schedule_pro_services_invoice(self, client: Metronome) -> None: - contract = client.v1.contracts.schedule_pro_services_invoice( - contract_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - customer_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - issued_at=parse_datetime("2019-12-27T18:11:19.117Z"), - line_items=[{"professional_service_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - ) - assert_matches_type(ContractScheduleProServicesInvoiceResponse, contract, path=["response"]) - - @parametrize - def test_method_schedule_pro_services_invoice_with_all_params(self, client: Metronome) -> None: - contract = client.v1.contracts.schedule_pro_services_invoice( - contract_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - customer_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - issued_at=parse_datetime("2019-12-27T18:11:19.117Z"), - line_items=[ - { - "professional_service_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "amendment_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "amount": 0, - "metadata": "metadata", - "netsuite_invoice_billing_end": parse_datetime("2019-12-27T18:11:19.117Z"), - "netsuite_invoice_billing_start": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 0, - "unit_price": 0, - } - ], - netsuite_invoice_header_end=parse_datetime("2019-12-27T18:11:19.117Z"), - netsuite_invoice_header_start=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(ContractScheduleProServicesInvoiceResponse, contract, path=["response"]) - - @parametrize - def test_raw_response_schedule_pro_services_invoice(self, client: Metronome) -> None: - response = client.v1.contracts.with_raw_response.schedule_pro_services_invoice( - contract_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - customer_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - issued_at=parse_datetime("2019-12-27T18:11:19.117Z"), - line_items=[{"professional_service_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = response.parse() - assert_matches_type(ContractScheduleProServicesInvoiceResponse, contract, path=["response"]) - - @parametrize - def test_streaming_response_schedule_pro_services_invoice(self, client: Metronome) -> None: - with client.v1.contracts.with_streaming_response.schedule_pro_services_invoice( - contract_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - customer_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - issued_at=parse_datetime("2019-12-27T18:11:19.117Z"), - line_items=[{"professional_service_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = response.parse() - assert_matches_type(ContractScheduleProServicesInvoiceResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_set_usage_filter(self, client: Metronome) -> None: - contract = client.v1.contracts.set_usage_filter( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - group_key="business_subscription_id", - group_values=["ID-1", "ID-2"], - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) - assert contract is None - - @parametrize - def test_raw_response_set_usage_filter(self, client: Metronome) -> None: - response = client.v1.contracts.with_raw_response.set_usage_filter( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - group_key="business_subscription_id", - group_values=["ID-1", "ID-2"], - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = response.parse() - assert contract is None - - @parametrize - def test_streaming_response_set_usage_filter(self, client: Metronome) -> None: - with client.v1.contracts.with_streaming_response.set_usage_filter( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - group_key="business_subscription_id", - group_values=["ID-1", "ID-2"], - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = response.parse() - assert contract is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_update_end_date(self, client: Metronome) -> None: - contract = client.v1.contracts.update_end_date( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(ContractUpdateEndDateResponse, contract, path=["response"]) - - @parametrize - def test_method_update_end_date_with_all_params(self, client: Metronome) -> None: - contract = client.v1.contracts.update_end_date( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - allow_ending_before_finalized_invoice=True, - ending_before=parse_datetime("2020-01-01T00:00:00.000Z"), - ) - assert_matches_type(ContractUpdateEndDateResponse, contract, path=["response"]) - - @parametrize - def test_raw_response_update_end_date(self, client: Metronome) -> None: - response = client.v1.contracts.with_raw_response.update_end_date( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = response.parse() - assert_matches_type(ContractUpdateEndDateResponse, contract, path=["response"]) - - @parametrize - def test_streaming_response_update_end_date(self, client: Metronome) -> None: - with client.v1.contracts.with_streaming_response.update_end_date( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = response.parse() - assert_matches_type(ContractUpdateEndDateResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncContracts: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v1.contracts.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) - assert_matches_type(ContractCreateResponse, contract, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v1.contracts.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - billing_provider_configuration={ - "billing_provider": "stripe", - "billing_provider_configuration_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "delivery_method": "direct_to_billing_provider", - }, - commits=[ - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "type": "PREPAID", - "access_schedule": { - "schedule_items": [ - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "amount": 0, - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "hierarchy_configuration": {"child_access": {"type": "ALL"}}, - "invoice_schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "do_not_invoice": True, - "recurring_schedule": { - "amount_distribution": "DIVIDED", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "frequency": "MONTHLY", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - "schedule_items": [ - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - } - ], - }, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "payment_gate_config": { - "payment_gate_type": "NONE", - "precalculated_tax_config": { - "tax_amount": 0, - "tax_name": "tax_name", - }, - "stripe_config": { - "payment_type": "INVOICE", - "invoice_metadata": {"foo": "string"}, - "on_session_payment": True, - }, - "tax_type": "NONE", - }, - "priority": 0, - "rate_type": "COMMIT_RATE", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - "temporary_id": "temporary_id", - } - ], - credits=[ - { - "access_schedule": { - "schedule_items": [ - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "hierarchy_configuration": {"child_access": {"type": "ALL"}}, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "priority": 0, - "rate_type": "COMMIT_RATE", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - } - ], - custom_fields={"foo": "string"}, - discounts=[ - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "do_not_invoice": True, - "recurring_schedule": { - "amount_distribution": "DIVIDED", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "frequency": "MONTHLY", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - "schedule_items": [ - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - } - ], - }, - "custom_fields": {"foo": "string"}, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - } - ], - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - hierarchy_configuration={ - "parent": { - "contract_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "customer_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "parent_behavior": {"invoice_consolidation_type": "CONCATENATE"}, - "payer": "SELF", - "usage_statement_behavior": "CONSOLIDATE", - }, - multiplier_override_prioritization="LOWEST_MULTIPLIER", - name="name", - net_payment_terms_days=0, - netsuite_sales_order_id="netsuite_sales_order_id", - overrides=[ - { - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "applicable_product_tags": ["string"], - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "entitled": True, - "is_commit_specific": True, - "multiplier": 0, - "override_specifiers": [ - { - "billing_frequency": "MONTHLY", - "commit_ids": ["string"], - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - "recurring_commit_ids": ["string"], - "recurring_credit_ids": ["string"], - } - ], - "overwrite_rate": { - "rate_type": "FLAT", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "custom_rate": {"foo": "bar"}, - "is_prorated": True, - "price": 0, - "quantity": 0, - "tiers": [ - { - "price": 0, - "size": 0, - } - ], - }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "target": "COMMIT_RATE", - "tiers": [ - { - "multiplier": 0, - "size": 0, - } - ], - "type": "OVERWRITE", - } - ], - package_alias="package_alias", - package_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - prepaid_balance_threshold_configuration={ - "commit": { - "product_id": "product_id", - "description": "description", - "name": "name", - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - }, - "is_enabled": True, - "payment_gate_config": { - "payment_gate_type": "NONE", - "precalculated_tax_config": { - "tax_amount": 0, - "tax_name": "tax_name", - }, - "stripe_config": { - "payment_type": "INVOICE", - "invoice_metadata": {"foo": "string"}, - }, - "tax_type": "NONE", - }, - "recharge_to_amount": 0, - "threshold_amount": 0, - "custom_credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - professional_services=[ - { - "max_amount": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "quantity": 0, - "unit_price": 0, - "custom_fields": {"foo": "string"}, - "description": "description", - "netsuite_sales_order_id": "netsuite_sales_order_id", - } - ], - rate_card_alias="rate_card_alias", - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - recurring_commits=[ - { - "access_amount": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "unit_price": 0, - "quantity": 0, - }, - "commit_duration": { - "value": 0, - "unit": "PERIODS", - }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "description": "description", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "hierarchy_configuration": {"child_access": {"type": "ALL"}}, - "invoice_amount": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "quantity": 0, - "unit_price": 0, - }, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "proration": "NONE", - "rate_type": "COMMIT_RATE", - "recurrence_frequency": "MONTHLY", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - "subscription_config": { - "apply_seat_increase_config": {"is_prorated": True}, - "subscription_id": "subscription_id", - "allocation": "INDIVIDUAL", - }, - "temporary_id": "temporary_id", - } - ], - recurring_credits=[ - { - "access_amount": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "unit_price": 0, - "quantity": 0, - }, - "commit_duration": { - "value": 0, - "unit": "PERIODS", - }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "description": "description", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "hierarchy_configuration": {"child_access": {"type": "ALL"}}, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "proration": "NONE", - "rate_type": "COMMIT_RATE", - "recurrence_frequency": "MONTHLY", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - "subscription_config": { - "apply_seat_increase_config": {"is_prorated": True}, - "subscription_id": "subscription_id", - "allocation": "INDIVIDUAL", - }, - "temporary_id": "temporary_id", - } - ], - reseller_royalties=[ - { - "fraction": 0, - "netsuite_reseller_id": "netsuite_reseller_id", - "reseller_type": "AWS", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "aws_options": { - "aws_account_number": "aws_account_number", - "aws_offer_id": "aws_offer_id", - "aws_payer_reference_id": "aws_payer_reference_id", - }, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "gcp_options": { - "gcp_account_id": "gcp_account_id", - "gcp_offer_id": "gcp_offer_id", - }, - "reseller_contract_value": 0, - } - ], - revenue_system_configuration={ - "delivery_method": "direct_to_billing_provider", - "provider": "netsuite", - "revenue_system_configuration_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - salesforce_opportunity_id="salesforce_opportunity_id", - scheduled_charges=[ - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "do_not_invoice": True, - "recurring_schedule": { - "amount_distribution": "DIVIDED", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "frequency": "MONTHLY", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - "schedule_items": [ - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - } - ], - }, - "custom_fields": {"foo": "string"}, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - } - ], - scheduled_charges_on_usage_invoices="ALL", - spend_threshold_configuration={ - "commit": { - "product_id": "product_id", - "description": "description", - "name": "name", - }, - "is_enabled": True, - "payment_gate_config": { - "payment_gate_type": "NONE", - "precalculated_tax_config": { - "tax_amount": 0, - "tax_name": "tax_name", - }, - "stripe_config": { - "payment_type": "INVOICE", - "invoice_metadata": {"foo": "string"}, - }, - "tax_type": "NONE", - }, - "threshold_amount": 0, - }, - subscriptions=[ - { - "collection_schedule": "ADVANCE", - "proration": { - "invoice_behavior": "BILL_IMMEDIATELY", - "is_prorated": True, - }, - "subscription_rate": { - "billing_frequency": "MONTHLY", - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "custom_fields": {"foo": "string"}, - "description": "description", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "initial_quantity": 0, - "name": "name", - "quantity_management_mode": "SEAT_BASED", - "seat_config": { - "initial_seat_ids": ["string"], - "seat_group_key": "seat_group_key", - "initial_unassigned_seats": 0, - }, - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "temporary_id": "temporary_id", - } - ], - total_contract_value=0, - transition={ - "from_contract_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "type": "SUPERSEDE", - "future_invoice_behavior": {"trueup": "REMOVE"}, - }, - uniqueness_key="x", - usage_filter={ - "group_key": "group_key", - "group_values": ["string"], - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - usage_statement_schedule={ - "frequency": "MONTHLY", - "billing_anchor_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "day": "FIRST_OF_MONTH", - "invoice_generation_starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - ) - assert_matches_type(ContractCreateResponse, contract, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.with_raw_response.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = await response.parse() - assert_matches_type(ContractCreateResponse, contract, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.with_streaming_response.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = await response.parse() - assert_matches_type(ContractCreateResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_retrieve(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v1.contracts.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(ContractRetrieveResponse, contract, path=["response"]) - - @parametrize - async def test_method_retrieve_with_all_params(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v1.contracts.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - include_balance=True, - include_ledgers=True, - ) - assert_matches_type(ContractRetrieveResponse, contract, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.with_raw_response.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = await response.parse() - assert_matches_type(ContractRetrieveResponse, contract, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.with_streaming_response.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = await response.parse() - assert_matches_type(ContractRetrieveResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_list(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v1.contracts.list( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) - assert_matches_type(ContractListResponse, contract, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v1.contracts.list( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - covering_date=parse_datetime("2019-12-27T18:11:19.117Z"), - include_archived=True, - include_balance=True, - include_ledgers=True, - starting_at=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(ContractListResponse, contract, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.with_raw_response.list( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = await response.parse() - assert_matches_type(ContractListResponse, contract, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.with_streaming_response.list( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = await response.parse() - assert_matches_type(ContractListResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_add_manual_balance_entry(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v1.contracts.add_manual_balance_entry( - id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - amount=-1000, - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - reason="Reason for entry", - segment_id="66368e29-3f97-4d15-a6e9-120897f0070a", - ) - assert contract is None - - @parametrize - async def test_method_add_manual_balance_entry_with_all_params(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v1.contracts.add_manual_balance_entry( - id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - amount=-1000, - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - reason="Reason for entry", - segment_id="66368e29-3f97-4d15-a6e9-120897f0070a", - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - per_group_amounts={"foo": 0}, - timestamp=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert contract is None - - @parametrize - async def test_raw_response_add_manual_balance_entry(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.with_raw_response.add_manual_balance_entry( - id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - amount=-1000, - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - reason="Reason for entry", - segment_id="66368e29-3f97-4d15-a6e9-120897f0070a", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = await response.parse() - assert contract is None - - @parametrize - async def test_streaming_response_add_manual_balance_entry(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.with_streaming_response.add_manual_balance_entry( - id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - amount=-1000, - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - reason="Reason for entry", - segment_id="66368e29-3f97-4d15-a6e9-120897f0070a", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = await response.parse() - assert contract is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_amend(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v1.contracts.amend( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) - assert_matches_type(ContractAmendResponse, contract, path=["response"]) - - @parametrize - async def test_method_amend_with_all_params(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v1.contracts.amend( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - commits=[ - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "type": "PREPAID", - "access_schedule": { - "schedule_items": [ - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "amount": 0, - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "hierarchy_configuration": {"child_access": {"type": "ALL"}}, - "invoice_schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "do_not_invoice": True, - "recurring_schedule": { - "amount_distribution": "DIVIDED", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "frequency": "MONTHLY", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - "schedule_items": [ - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - } - ], - }, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "payment_gate_config": { - "payment_gate_type": "NONE", - "precalculated_tax_config": { - "tax_amount": 0, - "tax_name": "tax_name", - }, - "stripe_config": { - "payment_type": "INVOICE", - "invoice_metadata": {"foo": "string"}, - "on_session_payment": True, - }, - "tax_type": "NONE", - }, - "priority": 0, - "rate_type": "COMMIT_RATE", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - "temporary_id": "temporary_id", - } - ], - credits=[ - { - "access_schedule": { - "schedule_items": [ - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "hierarchy_configuration": {"child_access": {"type": "ALL"}}, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "priority": 0, - "rate_type": "COMMIT_RATE", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - } - ], - custom_fields={"foo": "string"}, - discounts=[ - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "do_not_invoice": True, - "recurring_schedule": { - "amount_distribution": "DIVIDED", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "frequency": "MONTHLY", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - "schedule_items": [ - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - } - ], - }, - "custom_fields": {"foo": "string"}, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - } - ], - netsuite_sales_order_id="netsuite_sales_order_id", - overrides=[ - { - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "applicable_product_tags": ["string"], - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "entitled": True, - "is_commit_specific": True, - "multiplier": 0, - "override_specifiers": [ - { - "billing_frequency": "MONTHLY", - "commit_ids": ["string"], - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - "recurring_commit_ids": ["string"], - "recurring_credit_ids": ["string"], - } - ], - "overwrite_rate": { - "rate_type": "FLAT", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "custom_rate": {"foo": "bar"}, - "is_prorated": True, - "price": 0, - "quantity": 0, - "tiers": [ - { - "price": 0, - "size": 0, - } - ], - }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "target": "COMMIT_RATE", - "tiers": [ - { - "multiplier": 0, - "size": 0, - } - ], - "type": "OVERWRITE", - } - ], - professional_services=[ - { - "max_amount": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "quantity": 0, - "unit_price": 0, - "custom_fields": {"foo": "string"}, - "description": "description", - "netsuite_sales_order_id": "netsuite_sales_order_id", - } - ], - reseller_royalties=[ - { - "reseller_type": "AWS", - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "aws_options": { - "aws_account_number": "aws_account_number", - "aws_offer_id": "aws_offer_id", - "aws_payer_reference_id": "aws_payer_reference_id", - }, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "fraction": 0, - "gcp_options": { - "gcp_account_id": "gcp_account_id", - "gcp_offer_id": "gcp_offer_id", - }, - "netsuite_reseller_id": "netsuite_reseller_id", - "reseller_contract_value": 0, - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - salesforce_opportunity_id="salesforce_opportunity_id", - scheduled_charges=[ - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "do_not_invoice": True, - "recurring_schedule": { - "amount_distribution": "DIVIDED", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "frequency": "MONTHLY", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - "schedule_items": [ - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - } - ], - }, - "custom_fields": {"foo": "string"}, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - } - ], - total_contract_value=0, - ) - assert_matches_type(ContractAmendResponse, contract, path=["response"]) - - @parametrize - async def test_raw_response_amend(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.with_raw_response.amend( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = await response.parse() - assert_matches_type(ContractAmendResponse, contract, path=["response"]) - - @parametrize - async def test_streaming_response_amend(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.with_streaming_response.amend( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = await response.parse() - assert_matches_type(ContractAmendResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_archive(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v1.contracts.archive( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - void_invoices=True, - ) - assert_matches_type(ContractArchiveResponse, contract, path=["response"]) - - @parametrize - async def test_raw_response_archive(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.with_raw_response.archive( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - void_invoices=True, - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = await response.parse() - assert_matches_type(ContractArchiveResponse, contract, path=["response"]) - - @parametrize - async def test_streaming_response_archive(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.with_streaming_response.archive( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - void_invoices=True, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = await response.parse() - assert_matches_type(ContractArchiveResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_create_historical_invoices(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v1.contracts.create_historical_invoices( - invoices=[ - { - "contract_id": "d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - "credit_type_id": "2714e483-4ff1-48e4-9e25-ac732e8f24f2", - "customer_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", - "exclusive_end_date": parse_datetime("2020-02-01T00:00:00.000Z"), - "inclusive_start_date": parse_datetime("2020-01-01T00:00:00.000Z"), - "issue_date": parse_datetime("2020-02-01T00:00:00.000Z"), - "usage_line_items": [ - { - "exclusive_end_date": parse_datetime("2020-02-01T00:00:00.000Z"), - "inclusive_start_date": parse_datetime("2020-01-01T00:00:00.000Z"), - "product_id": "f14d6729-6a44-4b13-9908-9387f1918790", - } - ], - } - ], - preview=False, - ) - assert_matches_type(ContractCreateHistoricalInvoicesResponse, contract, path=["response"]) - - @parametrize - async def test_raw_response_create_historical_invoices(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.with_raw_response.create_historical_invoices( - invoices=[ - { - "contract_id": "d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - "credit_type_id": "2714e483-4ff1-48e4-9e25-ac732e8f24f2", - "customer_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", - "exclusive_end_date": parse_datetime("2020-02-01T00:00:00.000Z"), - "inclusive_start_date": parse_datetime("2020-01-01T00:00:00.000Z"), - "issue_date": parse_datetime("2020-02-01T00:00:00.000Z"), - "usage_line_items": [ - { - "exclusive_end_date": parse_datetime("2020-02-01T00:00:00.000Z"), - "inclusive_start_date": parse_datetime("2020-01-01T00:00:00.000Z"), - "product_id": "f14d6729-6a44-4b13-9908-9387f1918790", - } - ], - } - ], - preview=False, - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = await response.parse() - assert_matches_type(ContractCreateHistoricalInvoicesResponse, contract, path=["response"]) - - @parametrize - async def test_streaming_response_create_historical_invoices(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.with_streaming_response.create_historical_invoices( - invoices=[ - { - "contract_id": "d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - "credit_type_id": "2714e483-4ff1-48e4-9e25-ac732e8f24f2", - "customer_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", - "exclusive_end_date": parse_datetime("2020-02-01T00:00:00.000Z"), - "inclusive_start_date": parse_datetime("2020-01-01T00:00:00.000Z"), - "issue_date": parse_datetime("2020-02-01T00:00:00.000Z"), - "usage_line_items": [ - { - "exclusive_end_date": parse_datetime("2020-02-01T00:00:00.000Z"), - "inclusive_start_date": parse_datetime("2020-01-01T00:00:00.000Z"), - "product_id": "f14d6729-6a44-4b13-9908-9387f1918790", - } - ], - } - ], - preview=False, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = await response.parse() - assert_matches_type(ContractCreateHistoricalInvoicesResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_get_net_balance(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v1.contracts.get_net_balance( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(ContractGetNetBalanceResponse, contract, path=["response"]) - - @parametrize - async def test_method_get_net_balance_with_all_params(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v1.contracts.get_net_balance( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - credit_type_id="2714e483-4ff1-48e4-9e25-ac732e8f24f2", - filters=[ - { - "balance_types": ["CREDIT"], - "custom_fields": {"campaign": "free-trial"}, - "ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - }, - { - "balance_types": ["PREPAID_COMMIT", "POSTPAID_COMMIT"], - "custom_fields": {"campaign": "signup-promotion"}, - "ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - }, - ], - invoice_inclusion_mode="FINALIZED", - ) - assert_matches_type(ContractGetNetBalanceResponse, contract, path=["response"]) - - @parametrize - async def test_raw_response_get_net_balance(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.with_raw_response.get_net_balance( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = await response.parse() - assert_matches_type(ContractGetNetBalanceResponse, contract, path=["response"]) - - @parametrize - async def test_streaming_response_get_net_balance(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.with_streaming_response.get_net_balance( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = await response.parse() - assert_matches_type(ContractGetNetBalanceResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_list_balances(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v1.contracts.list_balances( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(AsyncBodyCursorPage[ContractListBalancesResponse], contract, path=["response"]) - - @parametrize - async def test_method_list_balances_with_all_params(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v1.contracts.list_balances( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - covering_date=parse_datetime("2019-12-27T18:11:19.117Z"), - effective_before=parse_datetime("2019-12-27T18:11:19.117Z"), - exclude_zero_balances=True, - include_archived=True, - include_balance=True, - include_contract_balances=True, - include_ledgers=True, - limit=1, - next_page="next_page", - starting_at=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(AsyncBodyCursorPage[ContractListBalancesResponse], contract, path=["response"]) - - @parametrize - async def test_raw_response_list_balances(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.with_raw_response.list_balances( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = await response.parse() - assert_matches_type(AsyncBodyCursorPage[ContractListBalancesResponse], contract, path=["response"]) - - @parametrize - async def test_streaming_response_list_balances(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.with_streaming_response.list_balances( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = await response.parse() - assert_matches_type(AsyncBodyCursorPage[ContractListBalancesResponse], contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_retrieve_rate_schedule(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v1.contracts.retrieve_rate_schedule( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(ContractRetrieveRateScheduleResponse, contract, path=["response"]) - - @parametrize - async def test_method_retrieve_rate_schedule_with_all_params(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v1.contracts.retrieve_rate_schedule( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - limit=1, - next_page="next_page", - at=parse_datetime("2020-01-01T00:00:00.000Z"), - selectors=[ - { - "billing_frequency": "MONTHLY", - "partial_pricing_group_values": { - "region": "us-west-2", - "cloud": "aws", - }, - "pricing_group_values": {"foo": "string"}, - "product_id": "d6300dbb-882e-4d2d-8dec-5125d16b65d0", - "product_tags": ["string"], - } - ], - ) - assert_matches_type(ContractRetrieveRateScheduleResponse, contract, path=["response"]) - - @parametrize - async def test_raw_response_retrieve_rate_schedule(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.with_raw_response.retrieve_rate_schedule( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = await response.parse() - assert_matches_type(ContractRetrieveRateScheduleResponse, contract, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve_rate_schedule(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.with_streaming_response.retrieve_rate_schedule( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = await response.parse() - assert_matches_type(ContractRetrieveRateScheduleResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_retrieve_subscription_quantity_history(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v1.contracts.retrieve_subscription_quantity_history( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - subscription_id="1a824d53-bde6-4d82-96d7-6347ff227d5c", - ) - assert_matches_type(ContractRetrieveSubscriptionQuantityHistoryResponse, contract, path=["response"]) - - @parametrize - async def test_raw_response_retrieve_subscription_quantity_history(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.with_raw_response.retrieve_subscription_quantity_history( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - subscription_id="1a824d53-bde6-4d82-96d7-6347ff227d5c", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = await response.parse() - assert_matches_type(ContractRetrieveSubscriptionQuantityHistoryResponse, contract, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve_subscription_quantity_history( - self, async_client: AsyncMetronome - ) -> None: - async with async_client.v1.contracts.with_streaming_response.retrieve_subscription_quantity_history( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - subscription_id="1a824d53-bde6-4d82-96d7-6347ff227d5c", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = await response.parse() - assert_matches_type(ContractRetrieveSubscriptionQuantityHistoryResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_schedule_pro_services_invoice(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v1.contracts.schedule_pro_services_invoice( - contract_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - customer_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - issued_at=parse_datetime("2019-12-27T18:11:19.117Z"), - line_items=[{"professional_service_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - ) - assert_matches_type(ContractScheduleProServicesInvoiceResponse, contract, path=["response"]) - - @parametrize - async def test_method_schedule_pro_services_invoice_with_all_params(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v1.contracts.schedule_pro_services_invoice( - contract_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - customer_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - issued_at=parse_datetime("2019-12-27T18:11:19.117Z"), - line_items=[ - { - "professional_service_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "amendment_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "amount": 0, - "metadata": "metadata", - "netsuite_invoice_billing_end": parse_datetime("2019-12-27T18:11:19.117Z"), - "netsuite_invoice_billing_start": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 0, - "unit_price": 0, - } - ], - netsuite_invoice_header_end=parse_datetime("2019-12-27T18:11:19.117Z"), - netsuite_invoice_header_start=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(ContractScheduleProServicesInvoiceResponse, contract, path=["response"]) - - @parametrize - async def test_raw_response_schedule_pro_services_invoice(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.with_raw_response.schedule_pro_services_invoice( - contract_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - customer_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - issued_at=parse_datetime("2019-12-27T18:11:19.117Z"), - line_items=[{"professional_service_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = await response.parse() - assert_matches_type(ContractScheduleProServicesInvoiceResponse, contract, path=["response"]) - - @parametrize - async def test_streaming_response_schedule_pro_services_invoice(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.with_streaming_response.schedule_pro_services_invoice( - contract_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - customer_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - issued_at=parse_datetime("2019-12-27T18:11:19.117Z"), - line_items=[{"professional_service_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = await response.parse() - assert_matches_type(ContractScheduleProServicesInvoiceResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_set_usage_filter(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v1.contracts.set_usage_filter( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - group_key="business_subscription_id", - group_values=["ID-1", "ID-2"], - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) - assert contract is None - - @parametrize - async def test_raw_response_set_usage_filter(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.with_raw_response.set_usage_filter( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - group_key="business_subscription_id", - group_values=["ID-1", "ID-2"], - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = await response.parse() - assert contract is None - - @parametrize - async def test_streaming_response_set_usage_filter(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.with_streaming_response.set_usage_filter( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - group_key="business_subscription_id", - group_values=["ID-1", "ID-2"], - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = await response.parse() - assert contract is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_update_end_date(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v1.contracts.update_end_date( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(ContractUpdateEndDateResponse, contract, path=["response"]) - - @parametrize - async def test_method_update_end_date_with_all_params(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v1.contracts.update_end_date( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - allow_ending_before_finalized_invoice=True, - ending_before=parse_datetime("2020-01-01T00:00:00.000Z"), - ) - assert_matches_type(ContractUpdateEndDateResponse, contract, path=["response"]) - - @parametrize - async def test_raw_response_update_end_date(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.contracts.with_raw_response.update_end_date( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = await response.parse() - assert_matches_type(ContractUpdateEndDateResponse, contract, path=["response"]) - - @parametrize - async def test_streaming_response_update_end_date(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.contracts.with_streaming_response.update_end_date( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = await response.parse() - assert_matches_type(ContractUpdateEndDateResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v1/test_credit_grants.py b/tests/api_resources/v1/test_credit_grants.py deleted file mode 100644 index 9124d8cc4..000000000 --- a/tests/api_resources/v1/test_credit_grants.py +++ /dev/null @@ -1,553 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome._utils import parse_datetime -from metronome.types.v1 import ( - CreditGrantEditResponse, - CreditGrantListResponse, - CreditGrantVoidResponse, - CreditGrantCreateResponse, - CreditGrantListEntriesResponse, -) -from metronome.pagination import ( - SyncCursorPage, - AsyncCursorPage, - SyncCursorPageWithoutLimit, - AsyncCursorPageWithoutLimit, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestCreditGrants: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Metronome) -> None: - credit_grant = client.v1.credit_grants.create( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - expires_at=parse_datetime("2022-04-01T00:00:00Z"), - grant_amount={ - "amount": 1000, - "credit_type_id": "5ae401dc-a648-4b49-9ac3-391bb5bc4d7b", - }, - name="Acme Corp Promotional Credit Grant", - paid_amount={ - "amount": 5000, - "credit_type_id": "2714e483-4ff1-48e4-9e25-ac732e8f24f2", - }, - priority=0.5, - ) - assert_matches_type(CreditGrantCreateResponse, credit_grant, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Metronome) -> None: - credit_grant = client.v1.credit_grants.create( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - expires_at=parse_datetime("2022-04-01T00:00:00Z"), - grant_amount={ - "amount": 1000, - "credit_type_id": "5ae401dc-a648-4b49-9ac3-391bb5bc4d7b", - }, - name="Acme Corp Promotional Credit Grant", - paid_amount={ - "amount": 5000, - "credit_type_id": "2714e483-4ff1-48e4-9e25-ac732e8f24f2", - }, - priority=0.5, - credit_grant_type="trial", - custom_fields={"foo": "string"}, - effective_at=parse_datetime("2022-02-01T00:00:00Z"), - invoice_date=parse_datetime("2019-12-27T18:11:19.117Z"), - product_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - reason="Incentivize new customer", - rollover_settings={ - "expires_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "priority": 0, - "rollover_amount": { - "type": "MAX_PERCENTAGE", - "value": 0, - }, - }, - uniqueness_key="x", - ) - assert_matches_type(CreditGrantCreateResponse, credit_grant, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Metronome) -> None: - response = client.v1.credit_grants.with_raw_response.create( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - expires_at=parse_datetime("2022-04-01T00:00:00Z"), - grant_amount={ - "amount": 1000, - "credit_type_id": "5ae401dc-a648-4b49-9ac3-391bb5bc4d7b", - }, - name="Acme Corp Promotional Credit Grant", - paid_amount={ - "amount": 5000, - "credit_type_id": "2714e483-4ff1-48e4-9e25-ac732e8f24f2", - }, - priority=0.5, - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - credit_grant = response.parse() - assert_matches_type(CreditGrantCreateResponse, credit_grant, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Metronome) -> None: - with client.v1.credit_grants.with_streaming_response.create( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - expires_at=parse_datetime("2022-04-01T00:00:00Z"), - grant_amount={ - "amount": 1000, - "credit_type_id": "5ae401dc-a648-4b49-9ac3-391bb5bc4d7b", - }, - name="Acme Corp Promotional Credit Grant", - paid_amount={ - "amount": 5000, - "credit_type_id": "2714e483-4ff1-48e4-9e25-ac732e8f24f2", - }, - priority=0.5, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - credit_grant = response.parse() - assert_matches_type(CreditGrantCreateResponse, credit_grant, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_list(self, client: Metronome) -> None: - credit_grant = client.v1.credit_grants.list() - assert_matches_type(SyncCursorPage[CreditGrantListResponse], credit_grant, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Metronome) -> None: - credit_grant = client.v1.credit_grants.list( - limit=1, - next_page="next_page", - credit_grant_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - credit_type_ids=["2714e483-4ff1-48e4-9e25-ac732e8f24f2"], - customer_ids=["d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", "0e5b8609-d901-4992-b394-c3c2e3f37b1c"], - effective_before=parse_datetime("2022-02-01T00:00:00Z"), - not_expiring_before=parse_datetime("2022-02-01T00:00:00Z"), - ) - assert_matches_type(SyncCursorPage[CreditGrantListResponse], credit_grant, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Metronome) -> None: - response = client.v1.credit_grants.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - credit_grant = response.parse() - assert_matches_type(SyncCursorPage[CreditGrantListResponse], credit_grant, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Metronome) -> None: - with client.v1.credit_grants.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - credit_grant = response.parse() - assert_matches_type(SyncCursorPage[CreditGrantListResponse], credit_grant, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_edit(self, client: Metronome) -> None: - credit_grant = client.v1.credit_grants.edit( - id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) - assert_matches_type(CreditGrantEditResponse, credit_grant, path=["response"]) - - @parametrize - def test_method_edit_with_all_params(self, client: Metronome) -> None: - credit_grant = client.v1.credit_grants.edit( - id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - credit_grant_type="credit_grant_type", - expires_at=parse_datetime("2022-04-01T00:00:00Z"), - name="Acme Corp Promotional Credit Grant", - ) - assert_matches_type(CreditGrantEditResponse, credit_grant, path=["response"]) - - @parametrize - def test_raw_response_edit(self, client: Metronome) -> None: - response = client.v1.credit_grants.with_raw_response.edit( - id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - credit_grant = response.parse() - assert_matches_type(CreditGrantEditResponse, credit_grant, path=["response"]) - - @parametrize - def test_streaming_response_edit(self, client: Metronome) -> None: - with client.v1.credit_grants.with_streaming_response.edit( - id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - credit_grant = response.parse() - assert_matches_type(CreditGrantEditResponse, credit_grant, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_list_entries(self, client: Metronome) -> None: - credit_grant = client.v1.credit_grants.list_entries() - assert_matches_type(SyncCursorPageWithoutLimit[CreditGrantListEntriesResponse], credit_grant, path=["response"]) - - @parametrize - def test_method_list_entries_with_all_params(self, client: Metronome) -> None: - credit_grant = client.v1.credit_grants.list_entries( - next_page="next_page", - sort="asc", - credit_type_ids=["2714e483-4ff1-48e4-9e25-ac732e8f24f2"], - customer_ids=["6a37bb88-8538-48c5-b37b-a41c836328bd"], - ending_before=parse_datetime("2021-02-01T00:00:00Z"), - starting_on=parse_datetime("2021-01-01T00:00:00Z"), - ) - assert_matches_type(SyncCursorPageWithoutLimit[CreditGrantListEntriesResponse], credit_grant, path=["response"]) - - @parametrize - def test_raw_response_list_entries(self, client: Metronome) -> None: - response = client.v1.credit_grants.with_raw_response.list_entries() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - credit_grant = response.parse() - assert_matches_type(SyncCursorPageWithoutLimit[CreditGrantListEntriesResponse], credit_grant, path=["response"]) - - @parametrize - def test_streaming_response_list_entries(self, client: Metronome) -> None: - with client.v1.credit_grants.with_streaming_response.list_entries() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - credit_grant = response.parse() - assert_matches_type( - SyncCursorPageWithoutLimit[CreditGrantListEntriesResponse], credit_grant, path=["response"] - ) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_void(self, client: Metronome) -> None: - credit_grant = client.v1.credit_grants.void( - id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) - assert_matches_type(CreditGrantVoidResponse, credit_grant, path=["response"]) - - @parametrize - def test_method_void_with_all_params(self, client: Metronome) -> None: - credit_grant = client.v1.credit_grants.void( - id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - release_uniqueness_key=True, - void_credit_purchase_invoice=True, - ) - assert_matches_type(CreditGrantVoidResponse, credit_grant, path=["response"]) - - @parametrize - def test_raw_response_void(self, client: Metronome) -> None: - response = client.v1.credit_grants.with_raw_response.void( - id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - credit_grant = response.parse() - assert_matches_type(CreditGrantVoidResponse, credit_grant, path=["response"]) - - @parametrize - def test_streaming_response_void(self, client: Metronome) -> None: - with client.v1.credit_grants.with_streaming_response.void( - id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - credit_grant = response.parse() - assert_matches_type(CreditGrantVoidResponse, credit_grant, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncCreditGrants: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncMetronome) -> None: - credit_grant = await async_client.v1.credit_grants.create( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - expires_at=parse_datetime("2022-04-01T00:00:00Z"), - grant_amount={ - "amount": 1000, - "credit_type_id": "5ae401dc-a648-4b49-9ac3-391bb5bc4d7b", - }, - name="Acme Corp Promotional Credit Grant", - paid_amount={ - "amount": 5000, - "credit_type_id": "2714e483-4ff1-48e4-9e25-ac732e8f24f2", - }, - priority=0.5, - ) - assert_matches_type(CreditGrantCreateResponse, credit_grant, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncMetronome) -> None: - credit_grant = await async_client.v1.credit_grants.create( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - expires_at=parse_datetime("2022-04-01T00:00:00Z"), - grant_amount={ - "amount": 1000, - "credit_type_id": "5ae401dc-a648-4b49-9ac3-391bb5bc4d7b", - }, - name="Acme Corp Promotional Credit Grant", - paid_amount={ - "amount": 5000, - "credit_type_id": "2714e483-4ff1-48e4-9e25-ac732e8f24f2", - }, - priority=0.5, - credit_grant_type="trial", - custom_fields={"foo": "string"}, - effective_at=parse_datetime("2022-02-01T00:00:00Z"), - invoice_date=parse_datetime("2019-12-27T18:11:19.117Z"), - product_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - reason="Incentivize new customer", - rollover_settings={ - "expires_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "priority": 0, - "rollover_amount": { - "type": "MAX_PERCENTAGE", - "value": 0, - }, - }, - uniqueness_key="x", - ) - assert_matches_type(CreditGrantCreateResponse, credit_grant, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.credit_grants.with_raw_response.create( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - expires_at=parse_datetime("2022-04-01T00:00:00Z"), - grant_amount={ - "amount": 1000, - "credit_type_id": "5ae401dc-a648-4b49-9ac3-391bb5bc4d7b", - }, - name="Acme Corp Promotional Credit Grant", - paid_amount={ - "amount": 5000, - "credit_type_id": "2714e483-4ff1-48e4-9e25-ac732e8f24f2", - }, - priority=0.5, - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - credit_grant = await response.parse() - assert_matches_type(CreditGrantCreateResponse, credit_grant, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.credit_grants.with_streaming_response.create( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - expires_at=parse_datetime("2022-04-01T00:00:00Z"), - grant_amount={ - "amount": 1000, - "credit_type_id": "5ae401dc-a648-4b49-9ac3-391bb5bc4d7b", - }, - name="Acme Corp Promotional Credit Grant", - paid_amount={ - "amount": 5000, - "credit_type_id": "2714e483-4ff1-48e4-9e25-ac732e8f24f2", - }, - priority=0.5, - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - credit_grant = await response.parse() - assert_matches_type(CreditGrantCreateResponse, credit_grant, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_list(self, async_client: AsyncMetronome) -> None: - credit_grant = await async_client.v1.credit_grants.list() - assert_matches_type(AsyncCursorPage[CreditGrantListResponse], credit_grant, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncMetronome) -> None: - credit_grant = await async_client.v1.credit_grants.list( - limit=1, - next_page="next_page", - credit_grant_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - credit_type_ids=["2714e483-4ff1-48e4-9e25-ac732e8f24f2"], - customer_ids=["d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", "0e5b8609-d901-4992-b394-c3c2e3f37b1c"], - effective_before=parse_datetime("2022-02-01T00:00:00Z"), - not_expiring_before=parse_datetime("2022-02-01T00:00:00Z"), - ) - assert_matches_type(AsyncCursorPage[CreditGrantListResponse], credit_grant, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.credit_grants.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - credit_grant = await response.parse() - assert_matches_type(AsyncCursorPage[CreditGrantListResponse], credit_grant, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.credit_grants.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - credit_grant = await response.parse() - assert_matches_type(AsyncCursorPage[CreditGrantListResponse], credit_grant, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_edit(self, async_client: AsyncMetronome) -> None: - credit_grant = await async_client.v1.credit_grants.edit( - id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) - assert_matches_type(CreditGrantEditResponse, credit_grant, path=["response"]) - - @parametrize - async def test_method_edit_with_all_params(self, async_client: AsyncMetronome) -> None: - credit_grant = await async_client.v1.credit_grants.edit( - id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - credit_grant_type="credit_grant_type", - expires_at=parse_datetime("2022-04-01T00:00:00Z"), - name="Acme Corp Promotional Credit Grant", - ) - assert_matches_type(CreditGrantEditResponse, credit_grant, path=["response"]) - - @parametrize - async def test_raw_response_edit(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.credit_grants.with_raw_response.edit( - id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - credit_grant = await response.parse() - assert_matches_type(CreditGrantEditResponse, credit_grant, path=["response"]) - - @parametrize - async def test_streaming_response_edit(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.credit_grants.with_streaming_response.edit( - id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - credit_grant = await response.parse() - assert_matches_type(CreditGrantEditResponse, credit_grant, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_list_entries(self, async_client: AsyncMetronome) -> None: - credit_grant = await async_client.v1.credit_grants.list_entries() - assert_matches_type( - AsyncCursorPageWithoutLimit[CreditGrantListEntriesResponse], credit_grant, path=["response"] - ) - - @parametrize - async def test_method_list_entries_with_all_params(self, async_client: AsyncMetronome) -> None: - credit_grant = await async_client.v1.credit_grants.list_entries( - next_page="next_page", - sort="asc", - credit_type_ids=["2714e483-4ff1-48e4-9e25-ac732e8f24f2"], - customer_ids=["6a37bb88-8538-48c5-b37b-a41c836328bd"], - ending_before=parse_datetime("2021-02-01T00:00:00Z"), - starting_on=parse_datetime("2021-01-01T00:00:00Z"), - ) - assert_matches_type( - AsyncCursorPageWithoutLimit[CreditGrantListEntriesResponse], credit_grant, path=["response"] - ) - - @parametrize - async def test_raw_response_list_entries(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.credit_grants.with_raw_response.list_entries() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - credit_grant = await response.parse() - assert_matches_type( - AsyncCursorPageWithoutLimit[CreditGrantListEntriesResponse], credit_grant, path=["response"] - ) - - @parametrize - async def test_streaming_response_list_entries(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.credit_grants.with_streaming_response.list_entries() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - credit_grant = await response.parse() - assert_matches_type( - AsyncCursorPageWithoutLimit[CreditGrantListEntriesResponse], credit_grant, path=["response"] - ) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_void(self, async_client: AsyncMetronome) -> None: - credit_grant = await async_client.v1.credit_grants.void( - id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) - assert_matches_type(CreditGrantVoidResponse, credit_grant, path=["response"]) - - @parametrize - async def test_method_void_with_all_params(self, async_client: AsyncMetronome) -> None: - credit_grant = await async_client.v1.credit_grants.void( - id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - release_uniqueness_key=True, - void_credit_purchase_invoice=True, - ) - assert_matches_type(CreditGrantVoidResponse, credit_grant, path=["response"]) - - @parametrize - async def test_raw_response_void(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.credit_grants.with_raw_response.void( - id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - credit_grant = await response.parse() - assert_matches_type(CreditGrantVoidResponse, credit_grant, path=["response"]) - - @parametrize - async def test_streaming_response_void(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.credit_grants.with_streaming_response.void( - id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - credit_grant = await response.parse() - assert_matches_type(CreditGrantVoidResponse, credit_grant, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v1/test_custom_fields.py b/tests/api_resources/v1/test_custom_fields.py deleted file mode 100644 index 0fd5237c7..000000000 --- a/tests/api_resources/v1/test_custom_fields.py +++ /dev/null @@ -1,387 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome.types.v1 import ( - CustomFieldListKeysResponse, -) -from metronome.pagination import SyncCursorPageWithoutLimit, AsyncCursorPageWithoutLimit - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestCustomFields: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_add_key(self, client: Metronome) -> None: - custom_field = client.v1.custom_fields.add_key( - enforce_uniqueness=True, - entity="customer", - key="x_account_id", - ) - assert custom_field is None - - @parametrize - def test_raw_response_add_key(self, client: Metronome) -> None: - response = client.v1.custom_fields.with_raw_response.add_key( - enforce_uniqueness=True, - entity="customer", - key="x_account_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - custom_field = response.parse() - assert custom_field is None - - @parametrize - def test_streaming_response_add_key(self, client: Metronome) -> None: - with client.v1.custom_fields.with_streaming_response.add_key( - enforce_uniqueness=True, - entity="customer", - key="x_account_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - custom_field = response.parse() - assert custom_field is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_delete_values(self, client: Metronome) -> None: - custom_field = client.v1.custom_fields.delete_values( - entity="customer", - entity_id="99594816-e8a5-4bca-be21-8d1de0f45120", - keys=["x_account_id"], - ) - assert custom_field is None - - @parametrize - def test_raw_response_delete_values(self, client: Metronome) -> None: - response = client.v1.custom_fields.with_raw_response.delete_values( - entity="customer", - entity_id="99594816-e8a5-4bca-be21-8d1de0f45120", - keys=["x_account_id"], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - custom_field = response.parse() - assert custom_field is None - - @parametrize - def test_streaming_response_delete_values(self, client: Metronome) -> None: - with client.v1.custom_fields.with_streaming_response.delete_values( - entity="customer", - entity_id="99594816-e8a5-4bca-be21-8d1de0f45120", - keys=["x_account_id"], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - custom_field = response.parse() - assert custom_field is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_list_keys(self, client: Metronome) -> None: - custom_field = client.v1.custom_fields.list_keys() - assert_matches_type(SyncCursorPageWithoutLimit[CustomFieldListKeysResponse], custom_field, path=["response"]) - - @parametrize - def test_method_list_keys_with_all_params(self, client: Metronome) -> None: - custom_field = client.v1.custom_fields.list_keys( - next_page="next_page", - entities=["customer"], - ) - assert_matches_type(SyncCursorPageWithoutLimit[CustomFieldListKeysResponse], custom_field, path=["response"]) - - @parametrize - def test_raw_response_list_keys(self, client: Metronome) -> None: - response = client.v1.custom_fields.with_raw_response.list_keys() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - custom_field = response.parse() - assert_matches_type(SyncCursorPageWithoutLimit[CustomFieldListKeysResponse], custom_field, path=["response"]) - - @parametrize - def test_streaming_response_list_keys(self, client: Metronome) -> None: - with client.v1.custom_fields.with_streaming_response.list_keys() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - custom_field = response.parse() - assert_matches_type( - SyncCursorPageWithoutLimit[CustomFieldListKeysResponse], custom_field, path=["response"] - ) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_remove_key(self, client: Metronome) -> None: - custom_field = client.v1.custom_fields.remove_key( - entity="customer", - key="x_account_id", - ) - assert custom_field is None - - @parametrize - def test_raw_response_remove_key(self, client: Metronome) -> None: - response = client.v1.custom_fields.with_raw_response.remove_key( - entity="customer", - key="x_account_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - custom_field = response.parse() - assert custom_field is None - - @parametrize - def test_streaming_response_remove_key(self, client: Metronome) -> None: - with client.v1.custom_fields.with_streaming_response.remove_key( - entity="customer", - key="x_account_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - custom_field = response.parse() - assert custom_field is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_set_values(self, client: Metronome) -> None: - custom_field = client.v1.custom_fields.set_values( - custom_fields={"x_account_id": "KyVnHhSBWl7eY2bl"}, - entity="customer", - entity_id="99594816-e8a5-4bca-be21-8d1de0f45120", - ) - assert custom_field is None - - @parametrize - def test_raw_response_set_values(self, client: Metronome) -> None: - response = client.v1.custom_fields.with_raw_response.set_values( - custom_fields={"x_account_id": "KyVnHhSBWl7eY2bl"}, - entity="customer", - entity_id="99594816-e8a5-4bca-be21-8d1de0f45120", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - custom_field = response.parse() - assert custom_field is None - - @parametrize - def test_streaming_response_set_values(self, client: Metronome) -> None: - with client.v1.custom_fields.with_streaming_response.set_values( - custom_fields={"x_account_id": "KyVnHhSBWl7eY2bl"}, - entity="customer", - entity_id="99594816-e8a5-4bca-be21-8d1de0f45120", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - custom_field = response.parse() - assert custom_field is None - - assert cast(Any, response.is_closed) is True - - -class TestAsyncCustomFields: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_add_key(self, async_client: AsyncMetronome) -> None: - custom_field = await async_client.v1.custom_fields.add_key( - enforce_uniqueness=True, - entity="customer", - key="x_account_id", - ) - assert custom_field is None - - @parametrize - async def test_raw_response_add_key(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.custom_fields.with_raw_response.add_key( - enforce_uniqueness=True, - entity="customer", - key="x_account_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - custom_field = await response.parse() - assert custom_field is None - - @parametrize - async def test_streaming_response_add_key(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.custom_fields.with_streaming_response.add_key( - enforce_uniqueness=True, - entity="customer", - key="x_account_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - custom_field = await response.parse() - assert custom_field is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_delete_values(self, async_client: AsyncMetronome) -> None: - custom_field = await async_client.v1.custom_fields.delete_values( - entity="customer", - entity_id="99594816-e8a5-4bca-be21-8d1de0f45120", - keys=["x_account_id"], - ) - assert custom_field is None - - @parametrize - async def test_raw_response_delete_values(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.custom_fields.with_raw_response.delete_values( - entity="customer", - entity_id="99594816-e8a5-4bca-be21-8d1de0f45120", - keys=["x_account_id"], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - custom_field = await response.parse() - assert custom_field is None - - @parametrize - async def test_streaming_response_delete_values(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.custom_fields.with_streaming_response.delete_values( - entity="customer", - entity_id="99594816-e8a5-4bca-be21-8d1de0f45120", - keys=["x_account_id"], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - custom_field = await response.parse() - assert custom_field is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_list_keys(self, async_client: AsyncMetronome) -> None: - custom_field = await async_client.v1.custom_fields.list_keys() - assert_matches_type(AsyncCursorPageWithoutLimit[CustomFieldListKeysResponse], custom_field, path=["response"]) - - @parametrize - async def test_method_list_keys_with_all_params(self, async_client: AsyncMetronome) -> None: - custom_field = await async_client.v1.custom_fields.list_keys( - next_page="next_page", - entities=["customer"], - ) - assert_matches_type(AsyncCursorPageWithoutLimit[CustomFieldListKeysResponse], custom_field, path=["response"]) - - @parametrize - async def test_raw_response_list_keys(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.custom_fields.with_raw_response.list_keys() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - custom_field = await response.parse() - assert_matches_type(AsyncCursorPageWithoutLimit[CustomFieldListKeysResponse], custom_field, path=["response"]) - - @parametrize - async def test_streaming_response_list_keys(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.custom_fields.with_streaming_response.list_keys() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - custom_field = await response.parse() - assert_matches_type( - AsyncCursorPageWithoutLimit[CustomFieldListKeysResponse], custom_field, path=["response"] - ) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_remove_key(self, async_client: AsyncMetronome) -> None: - custom_field = await async_client.v1.custom_fields.remove_key( - entity="customer", - key="x_account_id", - ) - assert custom_field is None - - @parametrize - async def test_raw_response_remove_key(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.custom_fields.with_raw_response.remove_key( - entity="customer", - key="x_account_id", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - custom_field = await response.parse() - assert custom_field is None - - @parametrize - async def test_streaming_response_remove_key(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.custom_fields.with_streaming_response.remove_key( - entity="customer", - key="x_account_id", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - custom_field = await response.parse() - assert custom_field is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_set_values(self, async_client: AsyncMetronome) -> None: - custom_field = await async_client.v1.custom_fields.set_values( - custom_fields={"x_account_id": "KyVnHhSBWl7eY2bl"}, - entity="customer", - entity_id="99594816-e8a5-4bca-be21-8d1de0f45120", - ) - assert custom_field is None - - @parametrize - async def test_raw_response_set_values(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.custom_fields.with_raw_response.set_values( - custom_fields={"x_account_id": "KyVnHhSBWl7eY2bl"}, - entity="customer", - entity_id="99594816-e8a5-4bca-be21-8d1de0f45120", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - custom_field = await response.parse() - assert custom_field is None - - @parametrize - async def test_streaming_response_set_values(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.custom_fields.with_streaming_response.set_values( - custom_fields={"x_account_id": "KyVnHhSBWl7eY2bl"}, - entity="customer", - entity_id="99594816-e8a5-4bca-be21-8d1de0f45120", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - custom_field = await response.parse() - assert custom_field is None - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v1/test_customers.py b/tests/api_resources/v1/test_customers.py deleted file mode 100644 index 2958de589..000000000 --- a/tests/api_resources/v1/test_customers.py +++ /dev/null @@ -1,1366 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome._utils import parse_datetime -from metronome.types.v1 import ( - CustomerDetail, - CustomerCreateResponse, - CustomerArchiveResponse, - CustomerSetNameResponse, - CustomerRetrieveResponse, - CustomerListCostsResponse, - CustomerPreviewEventsResponse, - CustomerListBillableMetricsResponse, - CustomerSetBillingConfigurationsResponse, - CustomerArchiveBillingConfigurationsResponse, - CustomerRetrieveBillingConfigurationsResponse, -) -from metronome.pagination import SyncCursorPage, AsyncCursorPage - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestCustomers: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Metronome) -> None: - customer = client.v1.customers.create( - name="Example, Inc.", - ) - assert_matches_type(CustomerCreateResponse, customer, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Metronome) -> None: - customer = client.v1.customers.create( - name="Example, Inc.", - billing_config={ - "billing_provider_customer_id": "billing_provider_customer_id", - "billing_provider_type": "aws_marketplace", - "aws_customer_account_id": "aws_customer_account_id", - "aws_customer_id": "aws_customer_id", - "aws_is_subscription_product": True, - "aws_product_code": "aws_product_code", - "aws_region": "af-south-1", - "stripe_collection_method": "charge_automatically", - }, - custom_fields={"foo": "string"}, - customer_billing_provider_configurations=[ - { - "billing_provider": "stripe", - "configuration": { - "stripe_customer_id": "bar", - "stripe_collection_method": "bar", - }, - "delivery_method": "direct_to_billing_provider", - "delivery_method_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "tax_provider": "anrok", - } - ], - customer_revenue_system_configurations=[ - { - "provider": "netsuite", - "configuration": {"foo": "bar"}, - "delivery_method": "direct_to_billing_provider", - "delivery_method_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - } - ], - external_id="x", - ingest_aliases=["team@example.com"], - ) - assert_matches_type(CustomerCreateResponse, customer, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Metronome) -> None: - response = client.v1.customers.with_raw_response.create( - name="Example, Inc.", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = response.parse() - assert_matches_type(CustomerCreateResponse, customer, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Metronome) -> None: - with client.v1.customers.with_streaming_response.create( - name="Example, Inc.", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = response.parse() - assert_matches_type(CustomerCreateResponse, customer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_retrieve(self, client: Metronome) -> None: - customer = client.v1.customers.retrieve( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(CustomerRetrieveResponse, customer, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Metronome) -> None: - response = client.v1.customers.with_raw_response.retrieve( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = response.parse() - assert_matches_type(CustomerRetrieveResponse, customer, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Metronome) -> None: - with client.v1.customers.with_streaming_response.retrieve( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = response.parse() - assert_matches_type(CustomerRetrieveResponse, customer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_retrieve(self, client: Metronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - client.v1.customers.with_raw_response.retrieve( - customer_id="", - ) - - @parametrize - def test_method_list(self, client: Metronome) -> None: - customer = client.v1.customers.list() - assert_matches_type(SyncCursorPage[CustomerDetail], customer, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Metronome) -> None: - customer = client.v1.customers.list( - customer_ids=["string"], - ingest_alias="ingest_alias", - limit=1, - next_page="next_page", - only_archived=True, - salesforce_account_ids=["string"], - ) - assert_matches_type(SyncCursorPage[CustomerDetail], customer, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Metronome) -> None: - response = client.v1.customers.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = response.parse() - assert_matches_type(SyncCursorPage[CustomerDetail], customer, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Metronome) -> None: - with client.v1.customers.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = response.parse() - assert_matches_type(SyncCursorPage[CustomerDetail], customer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_archive(self, client: Metronome) -> None: - customer = client.v1.customers.archive( - id="8deed800-1b7a-495d-a207-6c52bac54dc9", - ) - assert_matches_type(CustomerArchiveResponse, customer, path=["response"]) - - @parametrize - def test_raw_response_archive(self, client: Metronome) -> None: - response = client.v1.customers.with_raw_response.archive( - id="8deed800-1b7a-495d-a207-6c52bac54dc9", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = response.parse() - assert_matches_type(CustomerArchiveResponse, customer, path=["response"]) - - @parametrize - def test_streaming_response_archive(self, client: Metronome) -> None: - with client.v1.customers.with_streaming_response.archive( - id="8deed800-1b7a-495d-a207-6c52bac54dc9", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = response.parse() - assert_matches_type(CustomerArchiveResponse, customer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_archive_billing_configurations(self, client: Metronome) -> None: - customer = client.v1.customers.archive_billing_configurations( - customer_billing_provider_configuration_ids=[ - "4db51251-61de-4bfe-b9ce-495e244f3491", - "4db51251-61de-4bfe-b9ce-495e244f3491", - ], - customer_id="20a060d1-aa80-41d4-8bb2-4f3091b93903", - ) - assert_matches_type(CustomerArchiveBillingConfigurationsResponse, customer, path=["response"]) - - @parametrize - def test_raw_response_archive_billing_configurations(self, client: Metronome) -> None: - response = client.v1.customers.with_raw_response.archive_billing_configurations( - customer_billing_provider_configuration_ids=[ - "4db51251-61de-4bfe-b9ce-495e244f3491", - "4db51251-61de-4bfe-b9ce-495e244f3491", - ], - customer_id="20a060d1-aa80-41d4-8bb2-4f3091b93903", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = response.parse() - assert_matches_type(CustomerArchiveBillingConfigurationsResponse, customer, path=["response"]) - - @parametrize - def test_streaming_response_archive_billing_configurations(self, client: Metronome) -> None: - with client.v1.customers.with_streaming_response.archive_billing_configurations( - customer_billing_provider_configuration_ids=[ - "4db51251-61de-4bfe-b9ce-495e244f3491", - "4db51251-61de-4bfe-b9ce-495e244f3491", - ], - customer_id="20a060d1-aa80-41d4-8bb2-4f3091b93903", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = response.parse() - assert_matches_type(CustomerArchiveBillingConfigurationsResponse, customer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_list_billable_metrics(self, client: Metronome) -> None: - customer = client.v1.customers.list_billable_metrics( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(SyncCursorPage[CustomerListBillableMetricsResponse], customer, path=["response"]) - - @parametrize - def test_method_list_billable_metrics_with_all_params(self, client: Metronome) -> None: - customer = client.v1.customers.list_billable_metrics( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - include_archived=True, - limit=1, - next_page="next_page", - on_current_plan=True, - ) - assert_matches_type(SyncCursorPage[CustomerListBillableMetricsResponse], customer, path=["response"]) - - @parametrize - def test_raw_response_list_billable_metrics(self, client: Metronome) -> None: - response = client.v1.customers.with_raw_response.list_billable_metrics( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = response.parse() - assert_matches_type(SyncCursorPage[CustomerListBillableMetricsResponse], customer, path=["response"]) - - @parametrize - def test_streaming_response_list_billable_metrics(self, client: Metronome) -> None: - with client.v1.customers.with_streaming_response.list_billable_metrics( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = response.parse() - assert_matches_type(SyncCursorPage[CustomerListBillableMetricsResponse], customer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_list_billable_metrics(self, client: Metronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - client.v1.customers.with_raw_response.list_billable_metrics( - customer_id="", - ) - - @parametrize - def test_method_list_costs(self, client: Metronome) -> None: - customer = client.v1.customers.list_costs( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - starting_on=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(SyncCursorPage[CustomerListCostsResponse], customer, path=["response"]) - - @parametrize - def test_method_list_costs_with_all_params(self, client: Metronome) -> None: - customer = client.v1.customers.list_costs( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - starting_on=parse_datetime("2019-12-27T18:11:19.117Z"), - limit=1, - next_page="next_page", - ) - assert_matches_type(SyncCursorPage[CustomerListCostsResponse], customer, path=["response"]) - - @parametrize - def test_raw_response_list_costs(self, client: Metronome) -> None: - response = client.v1.customers.with_raw_response.list_costs( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - starting_on=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = response.parse() - assert_matches_type(SyncCursorPage[CustomerListCostsResponse], customer, path=["response"]) - - @parametrize - def test_streaming_response_list_costs(self, client: Metronome) -> None: - with client.v1.customers.with_streaming_response.list_costs( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - starting_on=parse_datetime("2019-12-27T18:11:19.117Z"), - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = response.parse() - assert_matches_type(SyncCursorPage[CustomerListCostsResponse], customer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_list_costs(self, client: Metronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - client.v1.customers.with_raw_response.list_costs( - customer_id="", - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - starting_on=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - - @parametrize - def test_method_preview_events(self, client: Metronome) -> None: - customer = client.v1.customers.preview_events( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - events=[{"event_type": "heartbeat"}], - ) - assert_matches_type(CustomerPreviewEventsResponse, customer, path=["response"]) - - @parametrize - def test_method_preview_events_with_all_params(self, client: Metronome) -> None: - customer = client.v1.customers.preview_events( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - events=[ - { - "event_type": "heartbeat", - "properties": { - "cpu_hours": "bar", - "memory_gb_hours": "bar", - }, - "timestamp": "2021-01-01T00:00:00Z", - "transaction_id": "x", - } - ], - mode="replace", - skip_zero_qty_line_items=True, - ) - assert_matches_type(CustomerPreviewEventsResponse, customer, path=["response"]) - - @parametrize - def test_raw_response_preview_events(self, client: Metronome) -> None: - response = client.v1.customers.with_raw_response.preview_events( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - events=[{"event_type": "heartbeat"}], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = response.parse() - assert_matches_type(CustomerPreviewEventsResponse, customer, path=["response"]) - - @parametrize - def test_streaming_response_preview_events(self, client: Metronome) -> None: - with client.v1.customers.with_streaming_response.preview_events( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - events=[{"event_type": "heartbeat"}], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = response.parse() - assert_matches_type(CustomerPreviewEventsResponse, customer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_preview_events(self, client: Metronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - client.v1.customers.with_raw_response.preview_events( - customer_id="", - events=[{"event_type": "heartbeat"}], - ) - - @parametrize - def test_method_retrieve_billing_configurations(self, client: Metronome) -> None: - customer = client.v1.customers.retrieve_billing_configurations( - customer_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) - assert_matches_type(CustomerRetrieveBillingConfigurationsResponse, customer, path=["response"]) - - @parametrize - def test_method_retrieve_billing_configurations_with_all_params(self, client: Metronome) -> None: - customer = client.v1.customers.retrieve_billing_configurations( - customer_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - include_archived=True, - ) - assert_matches_type(CustomerRetrieveBillingConfigurationsResponse, customer, path=["response"]) - - @parametrize - def test_raw_response_retrieve_billing_configurations(self, client: Metronome) -> None: - response = client.v1.customers.with_raw_response.retrieve_billing_configurations( - customer_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = response.parse() - assert_matches_type(CustomerRetrieveBillingConfigurationsResponse, customer, path=["response"]) - - @parametrize - def test_streaming_response_retrieve_billing_configurations(self, client: Metronome) -> None: - with client.v1.customers.with_streaming_response.retrieve_billing_configurations( - customer_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = response.parse() - assert_matches_type(CustomerRetrieveBillingConfigurationsResponse, customer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_set_billing_configurations(self, client: Metronome) -> None: - customer = client.v1.customers.set_billing_configurations( - data=[ - { - "billing_provider": "stripe", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "aws_marketplace", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "azure_marketplace", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "aws_marketplace", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "gcp_marketplace", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "netsuite", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - ], - ) - assert_matches_type(CustomerSetBillingConfigurationsResponse, customer, path=["response"]) - - @parametrize - def test_raw_response_set_billing_configurations(self, client: Metronome) -> None: - response = client.v1.customers.with_raw_response.set_billing_configurations( - data=[ - { - "billing_provider": "stripe", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "aws_marketplace", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "azure_marketplace", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "aws_marketplace", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "gcp_marketplace", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "netsuite", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - ], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = response.parse() - assert_matches_type(CustomerSetBillingConfigurationsResponse, customer, path=["response"]) - - @parametrize - def test_streaming_response_set_billing_configurations(self, client: Metronome) -> None: - with client.v1.customers.with_streaming_response.set_billing_configurations( - data=[ - { - "billing_provider": "stripe", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "aws_marketplace", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "azure_marketplace", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "aws_marketplace", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "gcp_marketplace", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "netsuite", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - ], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = response.parse() - assert_matches_type(CustomerSetBillingConfigurationsResponse, customer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_set_ingest_aliases(self, client: Metronome) -> None: - customer = client.v1.customers.set_ingest_aliases( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ingest_aliases=["team@example.com"], - ) - assert customer is None - - @parametrize - def test_raw_response_set_ingest_aliases(self, client: Metronome) -> None: - response = client.v1.customers.with_raw_response.set_ingest_aliases( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ingest_aliases=["team@example.com"], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = response.parse() - assert customer is None - - @parametrize - def test_streaming_response_set_ingest_aliases(self, client: Metronome) -> None: - with client.v1.customers.with_streaming_response.set_ingest_aliases( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ingest_aliases=["team@example.com"], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = response.parse() - assert customer is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_set_ingest_aliases(self, client: Metronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - client.v1.customers.with_raw_response.set_ingest_aliases( - customer_id="", - ingest_aliases=["team@example.com"], - ) - - @parametrize - def test_method_set_name(self, client: Metronome) -> None: - customer = client.v1.customers.set_name( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - name="Example, Inc.", - ) - assert_matches_type(CustomerSetNameResponse, customer, path=["response"]) - - @parametrize - def test_raw_response_set_name(self, client: Metronome) -> None: - response = client.v1.customers.with_raw_response.set_name( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - name="Example, Inc.", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = response.parse() - assert_matches_type(CustomerSetNameResponse, customer, path=["response"]) - - @parametrize - def test_streaming_response_set_name(self, client: Metronome) -> None: - with client.v1.customers.with_streaming_response.set_name( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - name="Example, Inc.", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = response.parse() - assert_matches_type(CustomerSetNameResponse, customer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_set_name(self, client: Metronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - client.v1.customers.with_raw_response.set_name( - customer_id="", - name="Example, Inc.", - ) - - @parametrize - def test_method_update_config(self, client: Metronome) -> None: - customer = client.v1.customers.update_config( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert customer is None - - @parametrize - def test_method_update_config_with_all_params(self, client: Metronome) -> None: - customer = client.v1.customers.update_config( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - leave_stripe_invoices_in_draft=True, - salesforce_account_id="0015500001WO1ZiABL", - ) - assert customer is None - - @parametrize - def test_raw_response_update_config(self, client: Metronome) -> None: - response = client.v1.customers.with_raw_response.update_config( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = response.parse() - assert customer is None - - @parametrize - def test_streaming_response_update_config(self, client: Metronome) -> None: - with client.v1.customers.with_streaming_response.update_config( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = response.parse() - assert customer is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_update_config(self, client: Metronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - client.v1.customers.with_raw_response.update_config( - customer_id="", - ) - - -class TestAsyncCustomers: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncMetronome) -> None: - customer = await async_client.v1.customers.create( - name="Example, Inc.", - ) - assert_matches_type(CustomerCreateResponse, customer, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncMetronome) -> None: - customer = await async_client.v1.customers.create( - name="Example, Inc.", - billing_config={ - "billing_provider_customer_id": "billing_provider_customer_id", - "billing_provider_type": "aws_marketplace", - "aws_customer_account_id": "aws_customer_account_id", - "aws_customer_id": "aws_customer_id", - "aws_is_subscription_product": True, - "aws_product_code": "aws_product_code", - "aws_region": "af-south-1", - "stripe_collection_method": "charge_automatically", - }, - custom_fields={"foo": "string"}, - customer_billing_provider_configurations=[ - { - "billing_provider": "stripe", - "configuration": { - "stripe_customer_id": "bar", - "stripe_collection_method": "bar", - }, - "delivery_method": "direct_to_billing_provider", - "delivery_method_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "tax_provider": "anrok", - } - ], - customer_revenue_system_configurations=[ - { - "provider": "netsuite", - "configuration": {"foo": "bar"}, - "delivery_method": "direct_to_billing_provider", - "delivery_method_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - } - ], - external_id="x", - ingest_aliases=["team@example.com"], - ) - assert_matches_type(CustomerCreateResponse, customer, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.with_raw_response.create( - name="Example, Inc.", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = await response.parse() - assert_matches_type(CustomerCreateResponse, customer, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.with_streaming_response.create( - name="Example, Inc.", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = await response.parse() - assert_matches_type(CustomerCreateResponse, customer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_retrieve(self, async_client: AsyncMetronome) -> None: - customer = await async_client.v1.customers.retrieve( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(CustomerRetrieveResponse, customer, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.with_raw_response.retrieve( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = await response.parse() - assert_matches_type(CustomerRetrieveResponse, customer, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.with_streaming_response.retrieve( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = await response.parse() - assert_matches_type(CustomerRetrieveResponse, customer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_retrieve(self, async_client: AsyncMetronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - await async_client.v1.customers.with_raw_response.retrieve( - customer_id="", - ) - - @parametrize - async def test_method_list(self, async_client: AsyncMetronome) -> None: - customer = await async_client.v1.customers.list() - assert_matches_type(AsyncCursorPage[CustomerDetail], customer, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncMetronome) -> None: - customer = await async_client.v1.customers.list( - customer_ids=["string"], - ingest_alias="ingest_alias", - limit=1, - next_page="next_page", - only_archived=True, - salesforce_account_ids=["string"], - ) - assert_matches_type(AsyncCursorPage[CustomerDetail], customer, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = await response.parse() - assert_matches_type(AsyncCursorPage[CustomerDetail], customer, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = await response.parse() - assert_matches_type(AsyncCursorPage[CustomerDetail], customer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_archive(self, async_client: AsyncMetronome) -> None: - customer = await async_client.v1.customers.archive( - id="8deed800-1b7a-495d-a207-6c52bac54dc9", - ) - assert_matches_type(CustomerArchiveResponse, customer, path=["response"]) - - @parametrize - async def test_raw_response_archive(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.with_raw_response.archive( - id="8deed800-1b7a-495d-a207-6c52bac54dc9", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = await response.parse() - assert_matches_type(CustomerArchiveResponse, customer, path=["response"]) - - @parametrize - async def test_streaming_response_archive(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.with_streaming_response.archive( - id="8deed800-1b7a-495d-a207-6c52bac54dc9", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = await response.parse() - assert_matches_type(CustomerArchiveResponse, customer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_archive_billing_configurations(self, async_client: AsyncMetronome) -> None: - customer = await async_client.v1.customers.archive_billing_configurations( - customer_billing_provider_configuration_ids=[ - "4db51251-61de-4bfe-b9ce-495e244f3491", - "4db51251-61de-4bfe-b9ce-495e244f3491", - ], - customer_id="20a060d1-aa80-41d4-8bb2-4f3091b93903", - ) - assert_matches_type(CustomerArchiveBillingConfigurationsResponse, customer, path=["response"]) - - @parametrize - async def test_raw_response_archive_billing_configurations(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.with_raw_response.archive_billing_configurations( - customer_billing_provider_configuration_ids=[ - "4db51251-61de-4bfe-b9ce-495e244f3491", - "4db51251-61de-4bfe-b9ce-495e244f3491", - ], - customer_id="20a060d1-aa80-41d4-8bb2-4f3091b93903", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = await response.parse() - assert_matches_type(CustomerArchiveBillingConfigurationsResponse, customer, path=["response"]) - - @parametrize - async def test_streaming_response_archive_billing_configurations(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.with_streaming_response.archive_billing_configurations( - customer_billing_provider_configuration_ids=[ - "4db51251-61de-4bfe-b9ce-495e244f3491", - "4db51251-61de-4bfe-b9ce-495e244f3491", - ], - customer_id="20a060d1-aa80-41d4-8bb2-4f3091b93903", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = await response.parse() - assert_matches_type(CustomerArchiveBillingConfigurationsResponse, customer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_list_billable_metrics(self, async_client: AsyncMetronome) -> None: - customer = await async_client.v1.customers.list_billable_metrics( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(AsyncCursorPage[CustomerListBillableMetricsResponse], customer, path=["response"]) - - @parametrize - async def test_method_list_billable_metrics_with_all_params(self, async_client: AsyncMetronome) -> None: - customer = await async_client.v1.customers.list_billable_metrics( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - include_archived=True, - limit=1, - next_page="next_page", - on_current_plan=True, - ) - assert_matches_type(AsyncCursorPage[CustomerListBillableMetricsResponse], customer, path=["response"]) - - @parametrize - async def test_raw_response_list_billable_metrics(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.with_raw_response.list_billable_metrics( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = await response.parse() - assert_matches_type(AsyncCursorPage[CustomerListBillableMetricsResponse], customer, path=["response"]) - - @parametrize - async def test_streaming_response_list_billable_metrics(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.with_streaming_response.list_billable_metrics( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = await response.parse() - assert_matches_type(AsyncCursorPage[CustomerListBillableMetricsResponse], customer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_list_billable_metrics(self, async_client: AsyncMetronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - await async_client.v1.customers.with_raw_response.list_billable_metrics( - customer_id="", - ) - - @parametrize - async def test_method_list_costs(self, async_client: AsyncMetronome) -> None: - customer = await async_client.v1.customers.list_costs( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - starting_on=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(AsyncCursorPage[CustomerListCostsResponse], customer, path=["response"]) - - @parametrize - async def test_method_list_costs_with_all_params(self, async_client: AsyncMetronome) -> None: - customer = await async_client.v1.customers.list_costs( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - starting_on=parse_datetime("2019-12-27T18:11:19.117Z"), - limit=1, - next_page="next_page", - ) - assert_matches_type(AsyncCursorPage[CustomerListCostsResponse], customer, path=["response"]) - - @parametrize - async def test_raw_response_list_costs(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.with_raw_response.list_costs( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - starting_on=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = await response.parse() - assert_matches_type(AsyncCursorPage[CustomerListCostsResponse], customer, path=["response"]) - - @parametrize - async def test_streaming_response_list_costs(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.with_streaming_response.list_costs( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - starting_on=parse_datetime("2019-12-27T18:11:19.117Z"), - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = await response.parse() - assert_matches_type(AsyncCursorPage[CustomerListCostsResponse], customer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_list_costs(self, async_client: AsyncMetronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - await async_client.v1.customers.with_raw_response.list_costs( - customer_id="", - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - starting_on=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - - @parametrize - async def test_method_preview_events(self, async_client: AsyncMetronome) -> None: - customer = await async_client.v1.customers.preview_events( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - events=[{"event_type": "heartbeat"}], - ) - assert_matches_type(CustomerPreviewEventsResponse, customer, path=["response"]) - - @parametrize - async def test_method_preview_events_with_all_params(self, async_client: AsyncMetronome) -> None: - customer = await async_client.v1.customers.preview_events( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - events=[ - { - "event_type": "heartbeat", - "properties": { - "cpu_hours": "bar", - "memory_gb_hours": "bar", - }, - "timestamp": "2021-01-01T00:00:00Z", - "transaction_id": "x", - } - ], - mode="replace", - skip_zero_qty_line_items=True, - ) - assert_matches_type(CustomerPreviewEventsResponse, customer, path=["response"]) - - @parametrize - async def test_raw_response_preview_events(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.with_raw_response.preview_events( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - events=[{"event_type": "heartbeat"}], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = await response.parse() - assert_matches_type(CustomerPreviewEventsResponse, customer, path=["response"]) - - @parametrize - async def test_streaming_response_preview_events(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.with_streaming_response.preview_events( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - events=[{"event_type": "heartbeat"}], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = await response.parse() - assert_matches_type(CustomerPreviewEventsResponse, customer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_preview_events(self, async_client: AsyncMetronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - await async_client.v1.customers.with_raw_response.preview_events( - customer_id="", - events=[{"event_type": "heartbeat"}], - ) - - @parametrize - async def test_method_retrieve_billing_configurations(self, async_client: AsyncMetronome) -> None: - customer = await async_client.v1.customers.retrieve_billing_configurations( - customer_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) - assert_matches_type(CustomerRetrieveBillingConfigurationsResponse, customer, path=["response"]) - - @parametrize - async def test_method_retrieve_billing_configurations_with_all_params(self, async_client: AsyncMetronome) -> None: - customer = await async_client.v1.customers.retrieve_billing_configurations( - customer_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - include_archived=True, - ) - assert_matches_type(CustomerRetrieveBillingConfigurationsResponse, customer, path=["response"]) - - @parametrize - async def test_raw_response_retrieve_billing_configurations(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.with_raw_response.retrieve_billing_configurations( - customer_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = await response.parse() - assert_matches_type(CustomerRetrieveBillingConfigurationsResponse, customer, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve_billing_configurations(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.with_streaming_response.retrieve_billing_configurations( - customer_id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = await response.parse() - assert_matches_type(CustomerRetrieveBillingConfigurationsResponse, customer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_set_billing_configurations(self, async_client: AsyncMetronome) -> None: - customer = await async_client.v1.customers.set_billing_configurations( - data=[ - { - "billing_provider": "stripe", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "aws_marketplace", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "azure_marketplace", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "aws_marketplace", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "gcp_marketplace", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "netsuite", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - ], - ) - assert_matches_type(CustomerSetBillingConfigurationsResponse, customer, path=["response"]) - - @parametrize - async def test_raw_response_set_billing_configurations(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.with_raw_response.set_billing_configurations( - data=[ - { - "billing_provider": "stripe", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "aws_marketplace", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "azure_marketplace", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "aws_marketplace", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "gcp_marketplace", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "netsuite", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - ], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = await response.parse() - assert_matches_type(CustomerSetBillingConfigurationsResponse, customer, path=["response"]) - - @parametrize - async def test_streaming_response_set_billing_configurations(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.with_streaming_response.set_billing_configurations( - data=[ - { - "billing_provider": "stripe", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "aws_marketplace", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "azure_marketplace", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "aws_marketplace", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "gcp_marketplace", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - { - "billing_provider": "netsuite", - "customer_id": "4db51251-61de-4bfe-b9ce-495e244f3491", - }, - ], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = await response.parse() - assert_matches_type(CustomerSetBillingConfigurationsResponse, customer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_set_ingest_aliases(self, async_client: AsyncMetronome) -> None: - customer = await async_client.v1.customers.set_ingest_aliases( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ingest_aliases=["team@example.com"], - ) - assert customer is None - - @parametrize - async def test_raw_response_set_ingest_aliases(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.with_raw_response.set_ingest_aliases( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ingest_aliases=["team@example.com"], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = await response.parse() - assert customer is None - - @parametrize - async def test_streaming_response_set_ingest_aliases(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.with_streaming_response.set_ingest_aliases( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ingest_aliases=["team@example.com"], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = await response.parse() - assert customer is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_set_ingest_aliases(self, async_client: AsyncMetronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - await async_client.v1.customers.with_raw_response.set_ingest_aliases( - customer_id="", - ingest_aliases=["team@example.com"], - ) - - @parametrize - async def test_method_set_name(self, async_client: AsyncMetronome) -> None: - customer = await async_client.v1.customers.set_name( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - name="Example, Inc.", - ) - assert_matches_type(CustomerSetNameResponse, customer, path=["response"]) - - @parametrize - async def test_raw_response_set_name(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.with_raw_response.set_name( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - name="Example, Inc.", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = await response.parse() - assert_matches_type(CustomerSetNameResponse, customer, path=["response"]) - - @parametrize - async def test_streaming_response_set_name(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.with_streaming_response.set_name( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - name="Example, Inc.", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = await response.parse() - assert_matches_type(CustomerSetNameResponse, customer, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_set_name(self, async_client: AsyncMetronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - await async_client.v1.customers.with_raw_response.set_name( - customer_id="", - name="Example, Inc.", - ) - - @parametrize - async def test_method_update_config(self, async_client: AsyncMetronome) -> None: - customer = await async_client.v1.customers.update_config( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert customer is None - - @parametrize - async def test_method_update_config_with_all_params(self, async_client: AsyncMetronome) -> None: - customer = await async_client.v1.customers.update_config( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - leave_stripe_invoices_in_draft=True, - salesforce_account_id="0015500001WO1ZiABL", - ) - assert customer is None - - @parametrize - async def test_raw_response_update_config(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.customers.with_raw_response.update_config( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - customer = await response.parse() - assert customer is None - - @parametrize - async def test_streaming_response_update_config(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.customers.with_streaming_response.update_config( - customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - customer = await response.parse() - assert customer is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_update_config(self, async_client: AsyncMetronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `customer_id` but received ''"): - await async_client.v1.customers.with_raw_response.update_config( - customer_id="", - ) diff --git a/tests/api_resources/v1/test_dashboards.py b/tests/api_resources/v1/test_dashboards.py deleted file mode 100644 index be9c73d6a..000000000 --- a/tests/api_resources/v1/test_dashboards.py +++ /dev/null @@ -1,160 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome.types.v1 import DashboardGetEmbeddableURLResponse - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestDashboards: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_get_embeddable_url(self, client: Metronome) -> None: - dashboard = client.v1.dashboards.get_embeddable_url( - customer_id="4db51251-61de-4bfe-b9ce-495e244f3491", - dashboard="invoices", - ) - assert_matches_type(DashboardGetEmbeddableURLResponse, dashboard, path=["response"]) - - @parametrize - def test_method_get_embeddable_url_with_all_params(self, client: Metronome) -> None: - dashboard = client.v1.dashboards.get_embeddable_url( - customer_id="4db51251-61de-4bfe-b9ce-495e244f3491", - dashboard="invoices", - bm_group_key_overrides=[ - { - "group_key_name": "tenant_id", - "display_name": "Org ID", - "value_display_names": { - "48ecb18f358f": "bar", - "e358f3ce242d": "bar", - }, - } - ], - color_overrides=[ - { - "name": "Gray_dark", - "value": "#ff0000", - } - ], - dashboard_options=[ - { - "key": "show_zero_usage_line_items", - "value": "false", - }, - { - "key": "hide_voided_invoices", - "value": "true", - }, - ], - ) - assert_matches_type(DashboardGetEmbeddableURLResponse, dashboard, path=["response"]) - - @parametrize - def test_raw_response_get_embeddable_url(self, client: Metronome) -> None: - response = client.v1.dashboards.with_raw_response.get_embeddable_url( - customer_id="4db51251-61de-4bfe-b9ce-495e244f3491", - dashboard="invoices", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - dashboard = response.parse() - assert_matches_type(DashboardGetEmbeddableURLResponse, dashboard, path=["response"]) - - @parametrize - def test_streaming_response_get_embeddable_url(self, client: Metronome) -> None: - with client.v1.dashboards.with_streaming_response.get_embeddable_url( - customer_id="4db51251-61de-4bfe-b9ce-495e244f3491", - dashboard="invoices", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - dashboard = response.parse() - assert_matches_type(DashboardGetEmbeddableURLResponse, dashboard, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncDashboards: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_get_embeddable_url(self, async_client: AsyncMetronome) -> None: - dashboard = await async_client.v1.dashboards.get_embeddable_url( - customer_id="4db51251-61de-4bfe-b9ce-495e244f3491", - dashboard="invoices", - ) - assert_matches_type(DashboardGetEmbeddableURLResponse, dashboard, path=["response"]) - - @parametrize - async def test_method_get_embeddable_url_with_all_params(self, async_client: AsyncMetronome) -> None: - dashboard = await async_client.v1.dashboards.get_embeddable_url( - customer_id="4db51251-61de-4bfe-b9ce-495e244f3491", - dashboard="invoices", - bm_group_key_overrides=[ - { - "group_key_name": "tenant_id", - "display_name": "Org ID", - "value_display_names": { - "48ecb18f358f": "bar", - "e358f3ce242d": "bar", - }, - } - ], - color_overrides=[ - { - "name": "Gray_dark", - "value": "#ff0000", - } - ], - dashboard_options=[ - { - "key": "show_zero_usage_line_items", - "value": "false", - }, - { - "key": "hide_voided_invoices", - "value": "true", - }, - ], - ) - assert_matches_type(DashboardGetEmbeddableURLResponse, dashboard, path=["response"]) - - @parametrize - async def test_raw_response_get_embeddable_url(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.dashboards.with_raw_response.get_embeddable_url( - customer_id="4db51251-61de-4bfe-b9ce-495e244f3491", - dashboard="invoices", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - dashboard = await response.parse() - assert_matches_type(DashboardGetEmbeddableURLResponse, dashboard, path=["response"]) - - @parametrize - async def test_streaming_response_get_embeddable_url(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.dashboards.with_streaming_response.get_embeddable_url( - customer_id="4db51251-61de-4bfe-b9ce-495e244f3491", - dashboard="invoices", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - dashboard = await response.parse() - assert_matches_type(DashboardGetEmbeddableURLResponse, dashboard, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v1/test_invoices.py b/tests/api_resources/v1/test_invoices.py deleted file mode 100644 index 0ab0c37bd..000000000 --- a/tests/api_resources/v1/test_invoices.py +++ /dev/null @@ -1,151 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome.types.v1 import ( - InvoiceVoidResponse, - InvoiceRegenerateResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestInvoices: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_regenerate(self, client: Metronome) -> None: - invoice = client.v1.invoices.regenerate( - id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) - assert_matches_type(InvoiceRegenerateResponse, invoice, path=["response"]) - - @parametrize - def test_raw_response_regenerate(self, client: Metronome) -> None: - response = client.v1.invoices.with_raw_response.regenerate( - id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - invoice = response.parse() - assert_matches_type(InvoiceRegenerateResponse, invoice, path=["response"]) - - @parametrize - def test_streaming_response_regenerate(self, client: Metronome) -> None: - with client.v1.invoices.with_streaming_response.regenerate( - id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - invoice = response.parse() - assert_matches_type(InvoiceRegenerateResponse, invoice, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_void(self, client: Metronome) -> None: - invoice = client.v1.invoices.void( - id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) - assert_matches_type(InvoiceVoidResponse, invoice, path=["response"]) - - @parametrize - def test_raw_response_void(self, client: Metronome) -> None: - response = client.v1.invoices.with_raw_response.void( - id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - invoice = response.parse() - assert_matches_type(InvoiceVoidResponse, invoice, path=["response"]) - - @parametrize - def test_streaming_response_void(self, client: Metronome) -> None: - with client.v1.invoices.with_streaming_response.void( - id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - invoice = response.parse() - assert_matches_type(InvoiceVoidResponse, invoice, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncInvoices: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_regenerate(self, async_client: AsyncMetronome) -> None: - invoice = await async_client.v1.invoices.regenerate( - id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) - assert_matches_type(InvoiceRegenerateResponse, invoice, path=["response"]) - - @parametrize - async def test_raw_response_regenerate(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.invoices.with_raw_response.regenerate( - id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - invoice = await response.parse() - assert_matches_type(InvoiceRegenerateResponse, invoice, path=["response"]) - - @parametrize - async def test_streaming_response_regenerate(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.invoices.with_streaming_response.regenerate( - id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - invoice = await response.parse() - assert_matches_type(InvoiceRegenerateResponse, invoice, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_void(self, async_client: AsyncMetronome) -> None: - invoice = await async_client.v1.invoices.void( - id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) - assert_matches_type(InvoiceVoidResponse, invoice, path=["response"]) - - @parametrize - async def test_raw_response_void(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.invoices.with_raw_response.void( - id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - invoice = await response.parse() - assert_matches_type(InvoiceVoidResponse, invoice, path=["response"]) - - @parametrize - async def test_streaming_response_void(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.invoices.with_streaming_response.void( - id="6a37bb88-8538-48c5-b37b-a41c836328bd", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - invoice = await response.parse() - assert_matches_type(InvoiceVoidResponse, invoice, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v1/test_packages.py b/tests/api_resources/v1/test_packages.py deleted file mode 100644 index 7a32ef573..000000000 --- a/tests/api_resources/v1/test_packages.py +++ /dev/null @@ -1,1122 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome._utils import parse_datetime -from metronome.types.v1 import ( - PackageListResponse, - PackageCreateResponse, - PackageArchiveResponse, - PackageRetrieveResponse, - PackageListContractsOnPackageResponse, -) -from metronome.pagination import SyncCursorPage, AsyncCursorPage - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestPackages: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_create(self, client: Metronome) -> None: - package = client.v1.packages.create( - name="My package", - ) - assert_matches_type(PackageCreateResponse, package, path=["response"]) - - @parametrize - def test_method_create_with_all_params(self, client: Metronome) -> None: - package = client.v1.packages.create( - name="My package", - aliases=[ - { - "name": "name", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - billing_anchor_date="contract_start_date", - billing_provider="stripe", - commits=[ - { - "access_schedule": { - "schedule_items": [ - { - "amount": 0, - "duration": { - "unit": "DAYS", - "value": 0, - }, - "starting_at_offset": { - "unit": "DAYS", - "value": 0, - }, - } - ], - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "type": "PREPAID", - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "invoice_schedule": { - "schedule_items": [ - { - "date_offset": { - "unit": "DAYS", - "value": 0, - }, - "quantity": 0, - "unit_price": 0, - } - ], - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "do_not_invoice": True, - }, - "name": "x", - "priority": 0, - "rate_type": "COMMIT_RATE", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - "temporary_id": "temporary_id", - } - ], - contract_name="contract_name", - credits=[ - { - "access_schedule": { - "schedule_items": [ - { - "amount": 0, - "duration": { - "unit": "DAYS", - "value": 0, - }, - "starting_at_offset": { - "unit": "DAYS", - "value": 0, - }, - } - ], - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "name": "x", - "priority": 0, - "rate_type": "COMMIT_RATE", - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - } - ], - delivery_method="direct_to_billing_provider", - duration={ - "unit": "DAYS", - "value": 0, - }, - multiplier_override_prioritization="LOWEST_MULTIPLIER", - net_payment_terms_days=0, - overrides=[ - { - "override_specifiers": [ - { - "billing_frequency": "MONTHLY", - "commit_ids": ["string"], - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - "recurring_commit_ids": ["string"], - "recurring_credit_ids": ["string"], - } - ], - "starting_at_offset": { - "unit": "DAYS", - "value": 0, - }, - "duration": { - "unit": "DAYS", - "value": 0, - }, - "entitled": True, - "is_commit_specific": True, - "multiplier": 0, - "overwrite_rate": { - "rate_type": "FLAT", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "custom_rate": {"foo": "bar"}, - "is_prorated": True, - "price": 0, - "quantity": 0, - "tiers": [ - { - "price": 0, - "size": 0, - } - ], - }, - "priority": 0, - "target": "COMMIT_RATE", - "tiers": [ - { - "multiplier": 0, - "size": 0, - } - ], - "type": "OVERWRITE", - } - ], - prepaid_balance_threshold_configuration={ - "commit": { - "product_id": "product_id", - "description": "description", - "name": "name", - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - }, - "is_enabled": True, - "payment_gate_config": { - "payment_gate_type": "NONE", - "precalculated_tax_config": { - "tax_amount": 0, - "tax_name": "tax_name", - }, - "stripe_config": { - "payment_type": "INVOICE", - "invoice_metadata": {"foo": "string"}, - }, - "tax_type": "NONE", - }, - "recharge_to_amount": 0, - "threshold_amount": 0, - "custom_credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - rate_card_alias="rate_card_alias", - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - recurring_commits=[ - { - "access_amount": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "unit_price": 0, - "quantity": 0, - }, - "commit_duration": { - "value": 0, - "unit": "PERIODS", - }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "starting_at_offset": { - "unit": "DAYS", - "value": 0, - }, - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "description": "description", - "duration": { - "unit": "DAYS", - "value": 0, - }, - "invoice_amount": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "quantity": 0, - "unit_price": 0, - }, - "name": "x", - "proration": "NONE", - "rate_type": "COMMIT_RATE", - "recurrence_frequency": "MONTHLY", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - "subscription_config": { - "apply_seat_increase_config": {"is_prorated": True}, - "subscription_id": "subscription_id", - "allocation": "INDIVIDUAL", - }, - "temporary_id": "temporary_id", - } - ], - recurring_credits=[ - { - "access_amount": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "unit_price": 0, - "quantity": 0, - }, - "commit_duration": { - "value": 0, - "unit": "PERIODS", - }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "starting_at_offset": { - "unit": "DAYS", - "value": 0, - }, - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "description": "description", - "duration": { - "unit": "DAYS", - "value": 0, - }, - "name": "x", - "proration": "NONE", - "rate_type": "COMMIT_RATE", - "recurrence_frequency": "MONTHLY", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - "subscription_config": { - "apply_seat_increase_config": {"is_prorated": True}, - "subscription_id": "subscription_id", - "allocation": "INDIVIDUAL", - }, - "temporary_id": "temporary_id", - } - ], - scheduled_charges=[ - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "schedule_items": [ - { - "date_offset": { - "unit": "DAYS", - "value": 0, - }, - "quantity": 0, - "unit_price": 0, - } - ], - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "custom_fields": {"foo": "string"}, - "name": "x", - } - ], - scheduled_charges_on_usage_invoices="ALL", - spend_threshold_configuration={ - "commit": { - "product_id": "product_id", - "description": "description", - "name": "name", - }, - "is_enabled": True, - "payment_gate_config": { - "payment_gate_type": "NONE", - "precalculated_tax_config": { - "tax_amount": 0, - "tax_name": "tax_name", - }, - "stripe_config": { - "payment_type": "INVOICE", - "invoice_metadata": {"foo": "string"}, - }, - "tax_type": "NONE", - }, - "threshold_amount": 0, - }, - subscriptions=[ - { - "collection_schedule": "ADVANCE", - "proration": { - "invoice_behavior": "BILL_IMMEDIATELY", - "is_prorated": True, - }, - "subscription_rate": { - "billing_frequency": "MONTHLY", - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "custom_fields": {"foo": "string"}, - "description": "description", - "duration": { - "unit": "DAYS", - "value": 0, - }, - "initial_quantity": 0, - "name": "name", - "quantity_management_mode": "SEAT_BASED", - "seat_config": { - "seat_group_key": "seat_group_key", - "initial_unassigned_seats": 0, - }, - "starting_at_offset": { - "unit": "DAYS", - "value": 0, - }, - "temporary_id": "temporary_id", - } - ], - uniqueness_key="x", - usage_statement_schedule={ - "frequency": "MONTHLY", - "day": "FIRST_OF_MONTH", - "invoice_generation_starting_at_offset": { - "unit": "DAYS", - "value": 0, - }, - }, - ) - assert_matches_type(PackageCreateResponse, package, path=["response"]) - - @parametrize - def test_raw_response_create(self, client: Metronome) -> None: - response = client.v1.packages.with_raw_response.create( - name="My package", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - package = response.parse() - assert_matches_type(PackageCreateResponse, package, path=["response"]) - - @parametrize - def test_streaming_response_create(self, client: Metronome) -> None: - with client.v1.packages.with_streaming_response.create( - name="My package", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - package = response.parse() - assert_matches_type(PackageCreateResponse, package, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_retrieve(self, client: Metronome) -> None: - package = client.v1.packages.retrieve( - package_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(PackageRetrieveResponse, package, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Metronome) -> None: - response = client.v1.packages.with_raw_response.retrieve( - package_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - package = response.parse() - assert_matches_type(PackageRetrieveResponse, package, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Metronome) -> None: - with client.v1.packages.with_streaming_response.retrieve( - package_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - package = response.parse() - assert_matches_type(PackageRetrieveResponse, package, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_list(self, client: Metronome) -> None: - package = client.v1.packages.list() - assert_matches_type(SyncCursorPage[PackageListResponse], package, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Metronome) -> None: - package = client.v1.packages.list( - limit=1, - next_page="next_page", - archive_filter="ARCHIVED", - ) - assert_matches_type(SyncCursorPage[PackageListResponse], package, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Metronome) -> None: - response = client.v1.packages.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - package = response.parse() - assert_matches_type(SyncCursorPage[PackageListResponse], package, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Metronome) -> None: - with client.v1.packages.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - package = response.parse() - assert_matches_type(SyncCursorPage[PackageListResponse], package, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_archive(self, client: Metronome) -> None: - package = client.v1.packages.archive( - package_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(PackageArchiveResponse, package, path=["response"]) - - @parametrize - def test_raw_response_archive(self, client: Metronome) -> None: - response = client.v1.packages.with_raw_response.archive( - package_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - package = response.parse() - assert_matches_type(PackageArchiveResponse, package, path=["response"]) - - @parametrize - def test_streaming_response_archive(self, client: Metronome) -> None: - with client.v1.packages.with_streaming_response.archive( - package_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - package = response.parse() - assert_matches_type(PackageArchiveResponse, package, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_list_contracts_on_package(self, client: Metronome) -> None: - package = client.v1.packages.list_contracts_on_package( - package_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(SyncCursorPage[PackageListContractsOnPackageResponse], package, path=["response"]) - - @parametrize - def test_method_list_contracts_on_package_with_all_params(self, client: Metronome) -> None: - package = client.v1.packages.list_contracts_on_package( - package_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - limit=1, - next_page="next_page", - covering_date=parse_datetime("2019-12-27T18:11:19.117Z"), - include_archived=True, - starting_at=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(SyncCursorPage[PackageListContractsOnPackageResponse], package, path=["response"]) - - @parametrize - def test_raw_response_list_contracts_on_package(self, client: Metronome) -> None: - response = client.v1.packages.with_raw_response.list_contracts_on_package( - package_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - package = response.parse() - assert_matches_type(SyncCursorPage[PackageListContractsOnPackageResponse], package, path=["response"]) - - @parametrize - def test_streaming_response_list_contracts_on_package(self, client: Metronome) -> None: - with client.v1.packages.with_streaming_response.list_contracts_on_package( - package_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - package = response.parse() - assert_matches_type(SyncCursorPage[PackageListContractsOnPackageResponse], package, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncPackages: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_create(self, async_client: AsyncMetronome) -> None: - package = await async_client.v1.packages.create( - name="My package", - ) - assert_matches_type(PackageCreateResponse, package, path=["response"]) - - @parametrize - async def test_method_create_with_all_params(self, async_client: AsyncMetronome) -> None: - package = await async_client.v1.packages.create( - name="My package", - aliases=[ - { - "name": "name", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - billing_anchor_date="contract_start_date", - billing_provider="stripe", - commits=[ - { - "access_schedule": { - "schedule_items": [ - { - "amount": 0, - "duration": { - "unit": "DAYS", - "value": 0, - }, - "starting_at_offset": { - "unit": "DAYS", - "value": 0, - }, - } - ], - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "type": "PREPAID", - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "invoice_schedule": { - "schedule_items": [ - { - "date_offset": { - "unit": "DAYS", - "value": 0, - }, - "quantity": 0, - "unit_price": 0, - } - ], - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "do_not_invoice": True, - }, - "name": "x", - "priority": 0, - "rate_type": "COMMIT_RATE", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - "temporary_id": "temporary_id", - } - ], - contract_name="contract_name", - credits=[ - { - "access_schedule": { - "schedule_items": [ - { - "amount": 0, - "duration": { - "unit": "DAYS", - "value": 0, - }, - "starting_at_offset": { - "unit": "DAYS", - "value": 0, - }, - } - ], - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "name": "x", - "priority": 0, - "rate_type": "COMMIT_RATE", - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - } - ], - delivery_method="direct_to_billing_provider", - duration={ - "unit": "DAYS", - "value": 0, - }, - multiplier_override_prioritization="LOWEST_MULTIPLIER", - net_payment_terms_days=0, - overrides=[ - { - "override_specifiers": [ - { - "billing_frequency": "MONTHLY", - "commit_ids": ["string"], - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - "recurring_commit_ids": ["string"], - "recurring_credit_ids": ["string"], - } - ], - "starting_at_offset": { - "unit": "DAYS", - "value": 0, - }, - "duration": { - "unit": "DAYS", - "value": 0, - }, - "entitled": True, - "is_commit_specific": True, - "multiplier": 0, - "overwrite_rate": { - "rate_type": "FLAT", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "custom_rate": {"foo": "bar"}, - "is_prorated": True, - "price": 0, - "quantity": 0, - "tiers": [ - { - "price": 0, - "size": 0, - } - ], - }, - "priority": 0, - "target": "COMMIT_RATE", - "tiers": [ - { - "multiplier": 0, - "size": 0, - } - ], - "type": "OVERWRITE", - } - ], - prepaid_balance_threshold_configuration={ - "commit": { - "product_id": "product_id", - "description": "description", - "name": "name", - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - }, - "is_enabled": True, - "payment_gate_config": { - "payment_gate_type": "NONE", - "precalculated_tax_config": { - "tax_amount": 0, - "tax_name": "tax_name", - }, - "stripe_config": { - "payment_type": "INVOICE", - "invoice_metadata": {"foo": "string"}, - }, - "tax_type": "NONE", - }, - "recharge_to_amount": 0, - "threshold_amount": 0, - "custom_credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - rate_card_alias="rate_card_alias", - rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - recurring_commits=[ - { - "access_amount": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "unit_price": 0, - "quantity": 0, - }, - "commit_duration": { - "value": 0, - "unit": "PERIODS", - }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "starting_at_offset": { - "unit": "DAYS", - "value": 0, - }, - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "description": "description", - "duration": { - "unit": "DAYS", - "value": 0, - }, - "invoice_amount": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "quantity": 0, - "unit_price": 0, - }, - "name": "x", - "proration": "NONE", - "rate_type": "COMMIT_RATE", - "recurrence_frequency": "MONTHLY", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - "subscription_config": { - "apply_seat_increase_config": {"is_prorated": True}, - "subscription_id": "subscription_id", - "allocation": "INDIVIDUAL", - }, - "temporary_id": "temporary_id", - } - ], - recurring_credits=[ - { - "access_amount": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "unit_price": 0, - "quantity": 0, - }, - "commit_duration": { - "value": 0, - "unit": "PERIODS", - }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "starting_at_offset": { - "unit": "DAYS", - "value": 0, - }, - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "description": "description", - "duration": { - "unit": "DAYS", - "value": 0, - }, - "name": "x", - "proration": "NONE", - "rate_type": "COMMIT_RATE", - "recurrence_frequency": "MONTHLY", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - "subscription_config": { - "apply_seat_increase_config": {"is_prorated": True}, - "subscription_id": "subscription_id", - "allocation": "INDIVIDUAL", - }, - "temporary_id": "temporary_id", - } - ], - scheduled_charges=[ - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "schedule_items": [ - { - "date_offset": { - "unit": "DAYS", - "value": 0, - }, - "quantity": 0, - "unit_price": 0, - } - ], - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "custom_fields": {"foo": "string"}, - "name": "x", - } - ], - scheduled_charges_on_usage_invoices="ALL", - spend_threshold_configuration={ - "commit": { - "product_id": "product_id", - "description": "description", - "name": "name", - }, - "is_enabled": True, - "payment_gate_config": { - "payment_gate_type": "NONE", - "precalculated_tax_config": { - "tax_amount": 0, - "tax_name": "tax_name", - }, - "stripe_config": { - "payment_type": "INVOICE", - "invoice_metadata": {"foo": "string"}, - }, - "tax_type": "NONE", - }, - "threshold_amount": 0, - }, - subscriptions=[ - { - "collection_schedule": "ADVANCE", - "proration": { - "invoice_behavior": "BILL_IMMEDIATELY", - "is_prorated": True, - }, - "subscription_rate": { - "billing_frequency": "MONTHLY", - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "custom_fields": {"foo": "string"}, - "description": "description", - "duration": { - "unit": "DAYS", - "value": 0, - }, - "initial_quantity": 0, - "name": "name", - "quantity_management_mode": "SEAT_BASED", - "seat_config": { - "seat_group_key": "seat_group_key", - "initial_unassigned_seats": 0, - }, - "starting_at_offset": { - "unit": "DAYS", - "value": 0, - }, - "temporary_id": "temporary_id", - } - ], - uniqueness_key="x", - usage_statement_schedule={ - "frequency": "MONTHLY", - "day": "FIRST_OF_MONTH", - "invoice_generation_starting_at_offset": { - "unit": "DAYS", - "value": 0, - }, - }, - ) - assert_matches_type(PackageCreateResponse, package, path=["response"]) - - @parametrize - async def test_raw_response_create(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.packages.with_raw_response.create( - name="My package", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - package = await response.parse() - assert_matches_type(PackageCreateResponse, package, path=["response"]) - - @parametrize - async def test_streaming_response_create(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.packages.with_streaming_response.create( - name="My package", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - package = await response.parse() - assert_matches_type(PackageCreateResponse, package, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_retrieve(self, async_client: AsyncMetronome) -> None: - package = await async_client.v1.packages.retrieve( - package_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(PackageRetrieveResponse, package, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.packages.with_raw_response.retrieve( - package_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - package = await response.parse() - assert_matches_type(PackageRetrieveResponse, package, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.packages.with_streaming_response.retrieve( - package_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - package = await response.parse() - assert_matches_type(PackageRetrieveResponse, package, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_list(self, async_client: AsyncMetronome) -> None: - package = await async_client.v1.packages.list() - assert_matches_type(AsyncCursorPage[PackageListResponse], package, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncMetronome) -> None: - package = await async_client.v1.packages.list( - limit=1, - next_page="next_page", - archive_filter="ARCHIVED", - ) - assert_matches_type(AsyncCursorPage[PackageListResponse], package, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.packages.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - package = await response.parse() - assert_matches_type(AsyncCursorPage[PackageListResponse], package, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.packages.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - package = await response.parse() - assert_matches_type(AsyncCursorPage[PackageListResponse], package, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_archive(self, async_client: AsyncMetronome) -> None: - package = await async_client.v1.packages.archive( - package_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(PackageArchiveResponse, package, path=["response"]) - - @parametrize - async def test_raw_response_archive(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.packages.with_raw_response.archive( - package_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - package = await response.parse() - assert_matches_type(PackageArchiveResponse, package, path=["response"]) - - @parametrize - async def test_streaming_response_archive(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.packages.with_streaming_response.archive( - package_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - package = await response.parse() - assert_matches_type(PackageArchiveResponse, package, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_list_contracts_on_package(self, async_client: AsyncMetronome) -> None: - package = await async_client.v1.packages.list_contracts_on_package( - package_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(AsyncCursorPage[PackageListContractsOnPackageResponse], package, path=["response"]) - - @parametrize - async def test_method_list_contracts_on_package_with_all_params(self, async_client: AsyncMetronome) -> None: - package = await async_client.v1.packages.list_contracts_on_package( - package_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - limit=1, - next_page="next_page", - covering_date=parse_datetime("2019-12-27T18:11:19.117Z"), - include_archived=True, - starting_at=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(AsyncCursorPage[PackageListContractsOnPackageResponse], package, path=["response"]) - - @parametrize - async def test_raw_response_list_contracts_on_package(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.packages.with_raw_response.list_contracts_on_package( - package_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - package = await response.parse() - assert_matches_type(AsyncCursorPage[PackageListContractsOnPackageResponse], package, path=["response"]) - - @parametrize - async def test_streaming_response_list_contracts_on_package(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.packages.with_streaming_response.list_contracts_on_package( - package_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - package = await response.parse() - assert_matches_type(AsyncCursorPage[PackageListContractsOnPackageResponse], package, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v1/test_payments.py b/tests/api_resources/v1/test_payments.py deleted file mode 100644 index a2285538c..000000000 --- a/tests/api_resources/v1/test_payments.py +++ /dev/null @@ -1,255 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome.types.v1 import ( - Payment, - PaymentCancelResponse, - PaymentAttemptResponse, -) -from metronome.pagination import SyncBodyCursorPage, AsyncBodyCursorPage - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestPayments: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_list(self, client: Metronome) -> None: - payment = client.v1.payments.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - invoice_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - ) - assert_matches_type(SyncBodyCursorPage[Payment], payment, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Metronome) -> None: - payment = client.v1.payments.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - invoice_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - limit=1, - next_page="next_page", - statuses=["pending", "requires_intervention"], - ) - assert_matches_type(SyncBodyCursorPage[Payment], payment, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Metronome) -> None: - response = client.v1.payments.with_raw_response.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - invoice_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - payment = response.parse() - assert_matches_type(SyncBodyCursorPage[Payment], payment, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Metronome) -> None: - with client.v1.payments.with_streaming_response.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - invoice_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - payment = response.parse() - assert_matches_type(SyncBodyCursorPage[Payment], payment, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_attempt(self, client: Metronome) -> None: - payment = client.v1.payments.attempt( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - invoice_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - ) - assert_matches_type(PaymentAttemptResponse, payment, path=["response"]) - - @parametrize - def test_raw_response_attempt(self, client: Metronome) -> None: - response = client.v1.payments.with_raw_response.attempt( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - invoice_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - payment = response.parse() - assert_matches_type(PaymentAttemptResponse, payment, path=["response"]) - - @parametrize - def test_streaming_response_attempt(self, client: Metronome) -> None: - with client.v1.payments.with_streaming_response.attempt( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - invoice_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - payment = response.parse() - assert_matches_type(PaymentAttemptResponse, payment, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_cancel(self, client: Metronome) -> None: - payment = client.v1.payments.cancel( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - invoice_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - ) - assert_matches_type(PaymentCancelResponse, payment, path=["response"]) - - @parametrize - def test_raw_response_cancel(self, client: Metronome) -> None: - response = client.v1.payments.with_raw_response.cancel( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - invoice_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - payment = response.parse() - assert_matches_type(PaymentCancelResponse, payment, path=["response"]) - - @parametrize - def test_streaming_response_cancel(self, client: Metronome) -> None: - with client.v1.payments.with_streaming_response.cancel( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - invoice_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - payment = response.parse() - assert_matches_type(PaymentCancelResponse, payment, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncPayments: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_list(self, async_client: AsyncMetronome) -> None: - payment = await async_client.v1.payments.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - invoice_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - ) - assert_matches_type(AsyncBodyCursorPage[Payment], payment, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncMetronome) -> None: - payment = await async_client.v1.payments.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - invoice_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - limit=1, - next_page="next_page", - statuses=["pending", "requires_intervention"], - ) - assert_matches_type(AsyncBodyCursorPage[Payment], payment, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.payments.with_raw_response.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - invoice_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - payment = await response.parse() - assert_matches_type(AsyncBodyCursorPage[Payment], payment, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.payments.with_streaming_response.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - invoice_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - payment = await response.parse() - assert_matches_type(AsyncBodyCursorPage[Payment], payment, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_attempt(self, async_client: AsyncMetronome) -> None: - payment = await async_client.v1.payments.attempt( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - invoice_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - ) - assert_matches_type(PaymentAttemptResponse, payment, path=["response"]) - - @parametrize - async def test_raw_response_attempt(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.payments.with_raw_response.attempt( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - invoice_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - payment = await response.parse() - assert_matches_type(PaymentAttemptResponse, payment, path=["response"]) - - @parametrize - async def test_streaming_response_attempt(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.payments.with_streaming_response.attempt( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - invoice_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - payment = await response.parse() - assert_matches_type(PaymentAttemptResponse, payment, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_cancel(self, async_client: AsyncMetronome) -> None: - payment = await async_client.v1.payments.cancel( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - invoice_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - ) - assert_matches_type(PaymentCancelResponse, payment, path=["response"]) - - @parametrize - async def test_raw_response_cancel(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.payments.with_raw_response.cancel( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - invoice_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - payment = await response.parse() - assert_matches_type(PaymentCancelResponse, payment, path=["response"]) - - @parametrize - async def test_streaming_response_cancel(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.payments.with_streaming_response.cancel( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - invoice_id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - payment = await response.parse() - assert_matches_type(PaymentCancelResponse, payment, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v1/test_plans.py b/tests/api_resources/v1/test_plans.py deleted file mode 100644 index a62a820a2..000000000 --- a/tests/api_resources/v1/test_plans.py +++ /dev/null @@ -1,362 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome.types.v1 import ( - PlanListResponse, - PlanGetDetailsResponse, - PlanListChargesResponse, - PlanListCustomersResponse, -) -from metronome.pagination import SyncCursorPage, AsyncCursorPage - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestPlans: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_list(self, client: Metronome) -> None: - plan = client.v1.plans.list() - assert_matches_type(SyncCursorPage[PlanListResponse], plan, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Metronome) -> None: - plan = client.v1.plans.list( - limit=1, - next_page="next_page", - ) - assert_matches_type(SyncCursorPage[PlanListResponse], plan, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Metronome) -> None: - response = client.v1.plans.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - plan = response.parse() - assert_matches_type(SyncCursorPage[PlanListResponse], plan, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Metronome) -> None: - with client.v1.plans.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - plan = response.parse() - assert_matches_type(SyncCursorPage[PlanListResponse], plan, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_get_details(self, client: Metronome) -> None: - plan = client.v1.plans.get_details( - plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(PlanGetDetailsResponse, plan, path=["response"]) - - @parametrize - def test_raw_response_get_details(self, client: Metronome) -> None: - response = client.v1.plans.with_raw_response.get_details( - plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - plan = response.parse() - assert_matches_type(PlanGetDetailsResponse, plan, path=["response"]) - - @parametrize - def test_streaming_response_get_details(self, client: Metronome) -> None: - with client.v1.plans.with_streaming_response.get_details( - plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - plan = response.parse() - assert_matches_type(PlanGetDetailsResponse, plan, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_get_details(self, client: Metronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"): - client.v1.plans.with_raw_response.get_details( - plan_id="", - ) - - @parametrize - def test_method_list_charges(self, client: Metronome) -> None: - plan = client.v1.plans.list_charges( - plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(SyncCursorPage[PlanListChargesResponse], plan, path=["response"]) - - @parametrize - def test_method_list_charges_with_all_params(self, client: Metronome) -> None: - plan = client.v1.plans.list_charges( - plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - limit=1, - next_page="next_page", - ) - assert_matches_type(SyncCursorPage[PlanListChargesResponse], plan, path=["response"]) - - @parametrize - def test_raw_response_list_charges(self, client: Metronome) -> None: - response = client.v1.plans.with_raw_response.list_charges( - plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - plan = response.parse() - assert_matches_type(SyncCursorPage[PlanListChargesResponse], plan, path=["response"]) - - @parametrize - def test_streaming_response_list_charges(self, client: Metronome) -> None: - with client.v1.plans.with_streaming_response.list_charges( - plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - plan = response.parse() - assert_matches_type(SyncCursorPage[PlanListChargesResponse], plan, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_list_charges(self, client: Metronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"): - client.v1.plans.with_raw_response.list_charges( - plan_id="", - ) - - @parametrize - def test_method_list_customers(self, client: Metronome) -> None: - plan = client.v1.plans.list_customers( - plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(SyncCursorPage[PlanListCustomersResponse], plan, path=["response"]) - - @parametrize - def test_method_list_customers_with_all_params(self, client: Metronome) -> None: - plan = client.v1.plans.list_customers( - plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - limit=1, - next_page="next_page", - status="all", - ) - assert_matches_type(SyncCursorPage[PlanListCustomersResponse], plan, path=["response"]) - - @parametrize - def test_raw_response_list_customers(self, client: Metronome) -> None: - response = client.v1.plans.with_raw_response.list_customers( - plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - plan = response.parse() - assert_matches_type(SyncCursorPage[PlanListCustomersResponse], plan, path=["response"]) - - @parametrize - def test_streaming_response_list_customers(self, client: Metronome) -> None: - with client.v1.plans.with_streaming_response.list_customers( - plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - plan = response.parse() - assert_matches_type(SyncCursorPage[PlanListCustomersResponse], plan, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_path_params_list_customers(self, client: Metronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"): - client.v1.plans.with_raw_response.list_customers( - plan_id="", - ) - - -class TestAsyncPlans: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_list(self, async_client: AsyncMetronome) -> None: - plan = await async_client.v1.plans.list() - assert_matches_type(AsyncCursorPage[PlanListResponse], plan, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncMetronome) -> None: - plan = await async_client.v1.plans.list( - limit=1, - next_page="next_page", - ) - assert_matches_type(AsyncCursorPage[PlanListResponse], plan, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.plans.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - plan = await response.parse() - assert_matches_type(AsyncCursorPage[PlanListResponse], plan, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.plans.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - plan = await response.parse() - assert_matches_type(AsyncCursorPage[PlanListResponse], plan, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_get_details(self, async_client: AsyncMetronome) -> None: - plan = await async_client.v1.plans.get_details( - plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(PlanGetDetailsResponse, plan, path=["response"]) - - @parametrize - async def test_raw_response_get_details(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.plans.with_raw_response.get_details( - plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - plan = await response.parse() - assert_matches_type(PlanGetDetailsResponse, plan, path=["response"]) - - @parametrize - async def test_streaming_response_get_details(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.plans.with_streaming_response.get_details( - plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - plan = await response.parse() - assert_matches_type(PlanGetDetailsResponse, plan, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_get_details(self, async_client: AsyncMetronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"): - await async_client.v1.plans.with_raw_response.get_details( - plan_id="", - ) - - @parametrize - async def test_method_list_charges(self, async_client: AsyncMetronome) -> None: - plan = await async_client.v1.plans.list_charges( - plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(AsyncCursorPage[PlanListChargesResponse], plan, path=["response"]) - - @parametrize - async def test_method_list_charges_with_all_params(self, async_client: AsyncMetronome) -> None: - plan = await async_client.v1.plans.list_charges( - plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - limit=1, - next_page="next_page", - ) - assert_matches_type(AsyncCursorPage[PlanListChargesResponse], plan, path=["response"]) - - @parametrize - async def test_raw_response_list_charges(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.plans.with_raw_response.list_charges( - plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - plan = await response.parse() - assert_matches_type(AsyncCursorPage[PlanListChargesResponse], plan, path=["response"]) - - @parametrize - async def test_streaming_response_list_charges(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.plans.with_streaming_response.list_charges( - plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - plan = await response.parse() - assert_matches_type(AsyncCursorPage[PlanListChargesResponse], plan, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_list_charges(self, async_client: AsyncMetronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"): - await async_client.v1.plans.with_raw_response.list_charges( - plan_id="", - ) - - @parametrize - async def test_method_list_customers(self, async_client: AsyncMetronome) -> None: - plan = await async_client.v1.plans.list_customers( - plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - assert_matches_type(AsyncCursorPage[PlanListCustomersResponse], plan, path=["response"]) - - @parametrize - async def test_method_list_customers_with_all_params(self, async_client: AsyncMetronome) -> None: - plan = await async_client.v1.plans.list_customers( - plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - limit=1, - next_page="next_page", - status="all", - ) - assert_matches_type(AsyncCursorPage[PlanListCustomersResponse], plan, path=["response"]) - - @parametrize - async def test_raw_response_list_customers(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.plans.with_raw_response.list_customers( - plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - plan = await response.parse() - assert_matches_type(AsyncCursorPage[PlanListCustomersResponse], plan, path=["response"]) - - @parametrize - async def test_streaming_response_list_customers(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.plans.with_streaming_response.list_customers( - plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - plan = await response.parse() - assert_matches_type(AsyncCursorPage[PlanListCustomersResponse], plan, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_path_params_list_customers(self, async_client: AsyncMetronome) -> None: - with pytest.raises(ValueError, match=r"Expected a non-empty value for `plan_id` but received ''"): - await async_client.v1.plans.with_raw_response.list_customers( - plan_id="", - ) diff --git a/tests/api_resources/v1/test_pricing_units.py b/tests/api_resources/v1/test_pricing_units.py deleted file mode 100644 index d53e604eb..000000000 --- a/tests/api_resources/v1/test_pricing_units.py +++ /dev/null @@ -1,91 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome.types.v1 import PricingUnitListResponse -from metronome.pagination import SyncCursorPage, AsyncCursorPage - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestPricingUnits: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_list(self, client: Metronome) -> None: - pricing_unit = client.v1.pricing_units.list() - assert_matches_type(SyncCursorPage[PricingUnitListResponse], pricing_unit, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Metronome) -> None: - pricing_unit = client.v1.pricing_units.list( - limit=1, - next_page="next_page", - ) - assert_matches_type(SyncCursorPage[PricingUnitListResponse], pricing_unit, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Metronome) -> None: - response = client.v1.pricing_units.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - pricing_unit = response.parse() - assert_matches_type(SyncCursorPage[PricingUnitListResponse], pricing_unit, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Metronome) -> None: - with client.v1.pricing_units.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - pricing_unit = response.parse() - assert_matches_type(SyncCursorPage[PricingUnitListResponse], pricing_unit, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncPricingUnits: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_list(self, async_client: AsyncMetronome) -> None: - pricing_unit = await async_client.v1.pricing_units.list() - assert_matches_type(AsyncCursorPage[PricingUnitListResponse], pricing_unit, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncMetronome) -> None: - pricing_unit = await async_client.v1.pricing_units.list( - limit=1, - next_page="next_page", - ) - assert_matches_type(AsyncCursorPage[PricingUnitListResponse], pricing_unit, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.pricing_units.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - pricing_unit = await response.parse() - assert_matches_type(AsyncCursorPage[PricingUnitListResponse], pricing_unit, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.pricing_units.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - pricing_unit = await response.parse() - assert_matches_type(AsyncCursorPage[PricingUnitListResponse], pricing_unit, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v1/test_services.py b/tests/api_resources/v1/test_services.py deleted file mode 100644 index e0d8ea9fb..000000000 --- a/tests/api_resources/v1/test_services.py +++ /dev/null @@ -1,74 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome.types.v1 import ServiceListResponse - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestServices: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_list(self, client: Metronome) -> None: - service = client.v1.services.list() - assert_matches_type(ServiceListResponse, service, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Metronome) -> None: - response = client.v1.services.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - service = response.parse() - assert_matches_type(ServiceListResponse, service, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Metronome) -> None: - with client.v1.services.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - service = response.parse() - assert_matches_type(ServiceListResponse, service, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncServices: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_list(self, async_client: AsyncMetronome) -> None: - service = await async_client.v1.services.list() - assert_matches_type(ServiceListResponse, service, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.services.with_raw_response.list() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - service = await response.parse() - assert_matches_type(ServiceListResponse, service, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.services.with_streaming_response.list() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - service = await response.parse() - assert_matches_type(ServiceListResponse, service, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v1/test_settings.py b/tests/api_resources/v1/test_settings.py deleted file mode 100644 index 29887d169..000000000 --- a/tests/api_resources/v1/test_settings.py +++ /dev/null @@ -1,126 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome.types.v1 import SettingUpsertAvalaraCredentialsResponse - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestSettings: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_upsert_avalara_credentials(self, client: Metronome) -> None: - setting = client.v1.settings.upsert_avalara_credentials( - avalara_environment="PRODUCTION", - avalara_password="my_password_123", - avalara_username="test@metronome.com", - delivery_method_ids=["9a906ebb-fbc7-42e8-8e29-53bfd2db3aca"], - ) - assert_matches_type(SettingUpsertAvalaraCredentialsResponse, setting, path=["response"]) - - @parametrize - def test_method_upsert_avalara_credentials_with_all_params(self, client: Metronome) -> None: - setting = client.v1.settings.upsert_avalara_credentials( - avalara_environment="PRODUCTION", - avalara_password="my_password_123", - avalara_username="test@metronome.com", - delivery_method_ids=["9a906ebb-fbc7-42e8-8e29-53bfd2db3aca"], - commit_transactions=True, - ) - assert_matches_type(SettingUpsertAvalaraCredentialsResponse, setting, path=["response"]) - - @parametrize - def test_raw_response_upsert_avalara_credentials(self, client: Metronome) -> None: - response = client.v1.settings.with_raw_response.upsert_avalara_credentials( - avalara_environment="PRODUCTION", - avalara_password="my_password_123", - avalara_username="test@metronome.com", - delivery_method_ids=["9a906ebb-fbc7-42e8-8e29-53bfd2db3aca"], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - setting = response.parse() - assert_matches_type(SettingUpsertAvalaraCredentialsResponse, setting, path=["response"]) - - @parametrize - def test_streaming_response_upsert_avalara_credentials(self, client: Metronome) -> None: - with client.v1.settings.with_streaming_response.upsert_avalara_credentials( - avalara_environment="PRODUCTION", - avalara_password="my_password_123", - avalara_username="test@metronome.com", - delivery_method_ids=["9a906ebb-fbc7-42e8-8e29-53bfd2db3aca"], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - setting = response.parse() - assert_matches_type(SettingUpsertAvalaraCredentialsResponse, setting, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncSettings: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_upsert_avalara_credentials(self, async_client: AsyncMetronome) -> None: - setting = await async_client.v1.settings.upsert_avalara_credentials( - avalara_environment="PRODUCTION", - avalara_password="my_password_123", - avalara_username="test@metronome.com", - delivery_method_ids=["9a906ebb-fbc7-42e8-8e29-53bfd2db3aca"], - ) - assert_matches_type(SettingUpsertAvalaraCredentialsResponse, setting, path=["response"]) - - @parametrize - async def test_method_upsert_avalara_credentials_with_all_params(self, async_client: AsyncMetronome) -> None: - setting = await async_client.v1.settings.upsert_avalara_credentials( - avalara_environment="PRODUCTION", - avalara_password="my_password_123", - avalara_username="test@metronome.com", - delivery_method_ids=["9a906ebb-fbc7-42e8-8e29-53bfd2db3aca"], - commit_transactions=True, - ) - assert_matches_type(SettingUpsertAvalaraCredentialsResponse, setting, path=["response"]) - - @parametrize - async def test_raw_response_upsert_avalara_credentials(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.settings.with_raw_response.upsert_avalara_credentials( - avalara_environment="PRODUCTION", - avalara_password="my_password_123", - avalara_username="test@metronome.com", - delivery_method_ids=["9a906ebb-fbc7-42e8-8e29-53bfd2db3aca"], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - setting = await response.parse() - assert_matches_type(SettingUpsertAvalaraCredentialsResponse, setting, path=["response"]) - - @parametrize - async def test_streaming_response_upsert_avalara_credentials(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.settings.with_streaming_response.upsert_avalara_credentials( - avalara_environment="PRODUCTION", - avalara_password="my_password_123", - avalara_username="test@metronome.com", - delivery_method_ids=["9a906ebb-fbc7-42e8-8e29-53bfd2db3aca"], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - setting = await response.parse() - assert_matches_type(SettingUpsertAvalaraCredentialsResponse, setting, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v1/test_usage.py b/tests/api_resources/v1/test_usage.py deleted file mode 100644 index dc4476936..000000000 --- a/tests/api_resources/v1/test_usage.py +++ /dev/null @@ -1,413 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome._utils import parse_datetime -from metronome.types.v1 import ( - UsageListResponse, - UsageSearchResponse, - UsageListWithGroupsResponse, -) -from metronome.pagination import ( - SyncCursorPage, - AsyncCursorPage, - SyncCursorPageWithoutLimit, - AsyncCursorPageWithoutLimit, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestUsage: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_list(self, client: Metronome) -> None: - usage = client.v1.usage.list( - ending_before=parse_datetime("2021-01-03T00:00:00Z"), - starting_on=parse_datetime("2021-01-01T00:00:00Z"), - window_size="HOUR", - ) - assert_matches_type(SyncCursorPageWithoutLimit[UsageListResponse], usage, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Metronome) -> None: - usage = client.v1.usage.list( - ending_before=parse_datetime("2021-01-03T00:00:00Z"), - starting_on=parse_datetime("2021-01-01T00:00:00Z"), - window_size="HOUR", - next_page="next_page", - billable_metrics=[ - { - "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "group_by": { - "key": "key", - "values": ["x"], - }, - } - ], - customer_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - ) - assert_matches_type(SyncCursorPageWithoutLimit[UsageListResponse], usage, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Metronome) -> None: - response = client.v1.usage.with_raw_response.list( - ending_before=parse_datetime("2021-01-03T00:00:00Z"), - starting_on=parse_datetime("2021-01-01T00:00:00Z"), - window_size="HOUR", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - usage = response.parse() - assert_matches_type(SyncCursorPageWithoutLimit[UsageListResponse], usage, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Metronome) -> None: - with client.v1.usage.with_streaming_response.list( - ending_before=parse_datetime("2021-01-03T00:00:00Z"), - starting_on=parse_datetime("2021-01-01T00:00:00Z"), - window_size="HOUR", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - usage = response.parse() - assert_matches_type(SyncCursorPageWithoutLimit[UsageListResponse], usage, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_ingest(self, client: Metronome) -> None: - usage = client.v1.usage.ingest() - assert usage is None - - @parametrize - def test_method_ingest_with_all_params(self, client: Metronome) -> None: - usage = client.v1.usage.ingest( - usage=[ - { - "customer_id": "team@example.com", - "event_type": "heartbeat", - "timestamp": "2021-01-01T00:00:00Z", - "transaction_id": "2021-01-01T00:00:00Z_cluster42", - "properties": { - "cluster_id": "bar", - "cpu_seconds": "bar", - "region": "bar", - }, - } - ], - ) - assert usage is None - - @parametrize - def test_raw_response_ingest(self, client: Metronome) -> None: - response = client.v1.usage.with_raw_response.ingest() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - usage = response.parse() - assert usage is None - - @parametrize - def test_streaming_response_ingest(self, client: Metronome) -> None: - with client.v1.usage.with_streaming_response.ingest() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - usage = response.parse() - assert usage is None - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_list_with_groups(self, client: Metronome) -> None: - usage = client.v1.usage.list_with_groups( - billable_metric_id="222796fd-d29c-429e-89b2-549fabda4ed6", - customer_id="04ca7e72-4229-4a6e-ab11-9f7376fccbcb", - window_size="HOUR", - ) - assert_matches_type(SyncCursorPage[UsageListWithGroupsResponse], usage, path=["response"]) - - @parametrize - def test_method_list_with_groups_with_all_params(self, client: Metronome) -> None: - usage = client.v1.usage.list_with_groups( - billable_metric_id="222796fd-d29c-429e-89b2-549fabda4ed6", - customer_id="04ca7e72-4229-4a6e-ab11-9f7376fccbcb", - window_size="HOUR", - limit=1, - next_page="next_page", - current_period=True, - ending_before=parse_datetime("2021-01-03T00:00:00Z"), - group_by={ - "key": "key", - "values": ["x"], - }, - group_filters={"region": ["us-east1", "us-west1"]}, - group_key=["region"], - starting_on=parse_datetime("2021-01-01T00:00:00Z"), - ) - assert_matches_type(SyncCursorPage[UsageListWithGroupsResponse], usage, path=["response"]) - - @parametrize - def test_raw_response_list_with_groups(self, client: Metronome) -> None: - response = client.v1.usage.with_raw_response.list_with_groups( - billable_metric_id="222796fd-d29c-429e-89b2-549fabda4ed6", - customer_id="04ca7e72-4229-4a6e-ab11-9f7376fccbcb", - window_size="HOUR", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - usage = response.parse() - assert_matches_type(SyncCursorPage[UsageListWithGroupsResponse], usage, path=["response"]) - - @parametrize - def test_streaming_response_list_with_groups(self, client: Metronome) -> None: - with client.v1.usage.with_streaming_response.list_with_groups( - billable_metric_id="222796fd-d29c-429e-89b2-549fabda4ed6", - customer_id="04ca7e72-4229-4a6e-ab11-9f7376fccbcb", - window_size="HOUR", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - usage = response.parse() - assert_matches_type(SyncCursorPage[UsageListWithGroupsResponse], usage, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_search(self, client: Metronome) -> None: - usage = client.v1.usage.search( - transaction_ids=["2021-01-01T00:00:00Z_cluster42"], - ) - assert_matches_type(UsageSearchResponse, usage, path=["response"]) - - @parametrize - def test_raw_response_search(self, client: Metronome) -> None: - response = client.v1.usage.with_raw_response.search( - transaction_ids=["2021-01-01T00:00:00Z_cluster42"], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - usage = response.parse() - assert_matches_type(UsageSearchResponse, usage, path=["response"]) - - @parametrize - def test_streaming_response_search(self, client: Metronome) -> None: - with client.v1.usage.with_streaming_response.search( - transaction_ids=["2021-01-01T00:00:00Z_cluster42"], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - usage = response.parse() - assert_matches_type(UsageSearchResponse, usage, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncUsage: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_list(self, async_client: AsyncMetronome) -> None: - usage = await async_client.v1.usage.list( - ending_before=parse_datetime("2021-01-03T00:00:00Z"), - starting_on=parse_datetime("2021-01-01T00:00:00Z"), - window_size="HOUR", - ) - assert_matches_type(AsyncCursorPageWithoutLimit[UsageListResponse], usage, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncMetronome) -> None: - usage = await async_client.v1.usage.list( - ending_before=parse_datetime("2021-01-03T00:00:00Z"), - starting_on=parse_datetime("2021-01-01T00:00:00Z"), - window_size="HOUR", - next_page="next_page", - billable_metrics=[ - { - "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "group_by": { - "key": "key", - "values": ["x"], - }, - } - ], - customer_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - ) - assert_matches_type(AsyncCursorPageWithoutLimit[UsageListResponse], usage, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.usage.with_raw_response.list( - ending_before=parse_datetime("2021-01-03T00:00:00Z"), - starting_on=parse_datetime("2021-01-01T00:00:00Z"), - window_size="HOUR", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - usage = await response.parse() - assert_matches_type(AsyncCursorPageWithoutLimit[UsageListResponse], usage, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.usage.with_streaming_response.list( - ending_before=parse_datetime("2021-01-03T00:00:00Z"), - starting_on=parse_datetime("2021-01-01T00:00:00Z"), - window_size="HOUR", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - usage = await response.parse() - assert_matches_type(AsyncCursorPageWithoutLimit[UsageListResponse], usage, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_ingest(self, async_client: AsyncMetronome) -> None: - usage = await async_client.v1.usage.ingest() - assert usage is None - - @parametrize - async def test_method_ingest_with_all_params(self, async_client: AsyncMetronome) -> None: - usage = await async_client.v1.usage.ingest( - usage=[ - { - "customer_id": "team@example.com", - "event_type": "heartbeat", - "timestamp": "2021-01-01T00:00:00Z", - "transaction_id": "2021-01-01T00:00:00Z_cluster42", - "properties": { - "cluster_id": "bar", - "cpu_seconds": "bar", - "region": "bar", - }, - } - ], - ) - assert usage is None - - @parametrize - async def test_raw_response_ingest(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.usage.with_raw_response.ingest() - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - usage = await response.parse() - assert usage is None - - @parametrize - async def test_streaming_response_ingest(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.usage.with_streaming_response.ingest() as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - usage = await response.parse() - assert usage is None - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_list_with_groups(self, async_client: AsyncMetronome) -> None: - usage = await async_client.v1.usage.list_with_groups( - billable_metric_id="222796fd-d29c-429e-89b2-549fabda4ed6", - customer_id="04ca7e72-4229-4a6e-ab11-9f7376fccbcb", - window_size="HOUR", - ) - assert_matches_type(AsyncCursorPage[UsageListWithGroupsResponse], usage, path=["response"]) - - @parametrize - async def test_method_list_with_groups_with_all_params(self, async_client: AsyncMetronome) -> None: - usage = await async_client.v1.usage.list_with_groups( - billable_metric_id="222796fd-d29c-429e-89b2-549fabda4ed6", - customer_id="04ca7e72-4229-4a6e-ab11-9f7376fccbcb", - window_size="HOUR", - limit=1, - next_page="next_page", - current_period=True, - ending_before=parse_datetime("2021-01-03T00:00:00Z"), - group_by={ - "key": "key", - "values": ["x"], - }, - group_filters={"region": ["us-east1", "us-west1"]}, - group_key=["region"], - starting_on=parse_datetime("2021-01-01T00:00:00Z"), - ) - assert_matches_type(AsyncCursorPage[UsageListWithGroupsResponse], usage, path=["response"]) - - @parametrize - async def test_raw_response_list_with_groups(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.usage.with_raw_response.list_with_groups( - billable_metric_id="222796fd-d29c-429e-89b2-549fabda4ed6", - customer_id="04ca7e72-4229-4a6e-ab11-9f7376fccbcb", - window_size="HOUR", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - usage = await response.parse() - assert_matches_type(AsyncCursorPage[UsageListWithGroupsResponse], usage, path=["response"]) - - @parametrize - async def test_streaming_response_list_with_groups(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.usage.with_streaming_response.list_with_groups( - billable_metric_id="222796fd-d29c-429e-89b2-549fabda4ed6", - customer_id="04ca7e72-4229-4a6e-ab11-9f7376fccbcb", - window_size="HOUR", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - usage = await response.parse() - assert_matches_type(AsyncCursorPage[UsageListWithGroupsResponse], usage, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_search(self, async_client: AsyncMetronome) -> None: - usage = await async_client.v1.usage.search( - transaction_ids=["2021-01-01T00:00:00Z_cluster42"], - ) - assert_matches_type(UsageSearchResponse, usage, path=["response"]) - - @parametrize - async def test_raw_response_search(self, async_client: AsyncMetronome) -> None: - response = await async_client.v1.usage.with_raw_response.search( - transaction_ids=["2021-01-01T00:00:00Z_cluster42"], - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - usage = await response.parse() - assert_matches_type(UsageSearchResponse, usage, path=["response"]) - - @parametrize - async def test_streaming_response_search(self, async_client: AsyncMetronome) -> None: - async with async_client.v1.usage.with_streaming_response.search( - transaction_ids=["2021-01-01T00:00:00Z_cluster42"], - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - usage = await response.parse() - assert_matches_type(UsageSearchResponse, usage, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/api_resources/v2/__init__.py b/tests/api_resources/v2/__init__.py deleted file mode 100644 index fd8019a9a..000000000 --- a/tests/api_resources/v2/__init__.py +++ /dev/null @@ -1 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. diff --git a/tests/api_resources/v2/test_contracts.py b/tests/api_resources/v2/test_contracts.py deleted file mode 100644 index c40117f6f..000000000 --- a/tests/api_resources/v2/test_contracts.py +++ /dev/null @@ -1,2038 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import Any, cast - -import pytest - -from metronome import Metronome, AsyncMetronome -from tests.utils import assert_matches_type -from metronome._utils import parse_datetime -from metronome.types.v2 import ( - ContractEditResponse, - ContractListResponse, - ContractRetrieveResponse, - ContractEditCommitResponse, - ContractEditCreditResponse, - ContractGetEditHistoryResponse, -) - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - - -class TestContracts: - parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) - - @parametrize - def test_method_retrieve(self, client: Metronome) -> None: - contract = client.v2.contracts.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(ContractRetrieveResponse, contract, path=["response"]) - - @parametrize - def test_method_retrieve_with_all_params(self, client: Metronome) -> None: - contract = client.v2.contracts.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - as_of_date=parse_datetime("2019-12-27T18:11:19.117Z"), - include_balance=True, - include_ledgers=True, - ) - assert_matches_type(ContractRetrieveResponse, contract, path=["response"]) - - @parametrize - def test_raw_response_retrieve(self, client: Metronome) -> None: - response = client.v2.contracts.with_raw_response.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = response.parse() - assert_matches_type(ContractRetrieveResponse, contract, path=["response"]) - - @parametrize - def test_streaming_response_retrieve(self, client: Metronome) -> None: - with client.v2.contracts.with_streaming_response.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = response.parse() - assert_matches_type(ContractRetrieveResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_list(self, client: Metronome) -> None: - contract = client.v2.contracts.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(ContractListResponse, contract, path=["response"]) - - @parametrize - def test_method_list_with_all_params(self, client: Metronome) -> None: - contract = client.v2.contracts.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - covering_date=parse_datetime("2019-12-27T18:11:19.117Z"), - include_archived=True, - include_balance=True, - include_ledgers=True, - starting_at=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(ContractListResponse, contract, path=["response"]) - - @parametrize - def test_raw_response_list(self, client: Metronome) -> None: - response = client.v2.contracts.with_raw_response.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = response.parse() - assert_matches_type(ContractListResponse, contract, path=["response"]) - - @parametrize - def test_streaming_response_list(self, client: Metronome) -> None: - with client.v2.contracts.with_streaming_response.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = response.parse() - assert_matches_type(ContractListResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_edit(self, client: Metronome) -> None: - contract = client.v2.contracts.edit( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(ContractEditResponse, contract, path=["response"]) - - @parametrize - def test_method_edit_with_all_params(self, client: Metronome) -> None: - contract = client.v2.contracts.edit( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - add_billing_provider_configuration_update={ - "billing_provider_configuration": { - "billing_provider": "aws_marketplace", - "billing_provider_configuration_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "delivery_method": "direct_to_billing_provider", - }, - "schedule": {"effective_at": "START_OF_CURRENT_PERIOD"}, - }, - add_commits=[ - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "type": "PREPAID", - "access_schedule": { - "schedule_items": [ - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "amount": 0, - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "hierarchy_configuration": {"child_access": {"type": "ALL"}}, - "invoice_schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "do_not_invoice": True, - "recurring_schedule": { - "amount_distribution": "DIVIDED", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "frequency": "MONTHLY", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - "schedule_items": [ - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - } - ], - }, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "payment_gate_config": { - "payment_gate_type": "NONE", - "precalculated_tax_config": { - "tax_amount": 0, - "tax_name": "tax_name", - }, - "stripe_config": { - "payment_type": "INVOICE", - "invoice_metadata": {"foo": "string"}, - "on_session_payment": True, - }, - "tax_type": "NONE", - }, - "priority": 0, - "rate_type": "COMMIT_RATE", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - "temporary_id": "temporary_id", - } - ], - add_credits=[ - { - "access_schedule": { - "schedule_items": [ - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "hierarchy_configuration": {"child_access": {"type": "ALL"}}, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "priority": 0, - "rate_type": "COMMIT_RATE", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - } - ], - add_discounts=[ - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "do_not_invoice": True, - "recurring_schedule": { - "amount_distribution": "DIVIDED", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "frequency": "MONTHLY", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - "schedule_items": [ - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - } - ], - }, - "custom_fields": {"foo": "string"}, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - } - ], - add_overrides=[ - { - "starting_at": parse_datetime("2024-11-02T00:00:00Z"), - "applicable_product_tags": ["string"], - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "entitled": True, - "is_commit_specific": True, - "multiplier": 2, - "override_specifiers": [ - { - "billing_frequency": "MONTHLY", - "commit_ids": ["string"], - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - "recurring_commit_ids": ["string"], - "recurring_credit_ids": ["string"], - } - ], - "overwrite_rate": { - "rate_type": "FLAT", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "custom_rate": {"foo": "bar"}, - "is_prorated": True, - "price": 0, - "quantity": 0, - "tiers": [ - { - "price": 0, - "size": 0, - } - ], - }, - "priority": 100, - "product_id": "d4fc086c-d8e5-4091-a235-fbba5da4ec14", - "target": "COMMIT_RATE", - "tiers": [ - { - "multiplier": 0, - "size": 0, - } - ], - "type": "MULTIPLIER", - } - ], - add_prepaid_balance_threshold_configuration={ - "commit": { - "description": "description", - "name": "name", - "product_id": "product_id", - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - }, - "is_enabled": True, - "payment_gate_config": { - "payment_gate_type": "NONE", - "precalculated_tax_config": { - "tax_amount": 0, - "tax_name": "tax_name", - }, - "stripe_config": { - "payment_type": "INVOICE", - "invoice_metadata": {"foo": "string"}, - }, - "tax_type": "NONE", - }, - "recharge_to_amount": 0, - "threshold_amount": 0, - "custom_credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - add_professional_services=[ - { - "max_amount": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "quantity": 0, - "unit_price": 0, - "custom_fields": {"foo": "string"}, - "description": "description", - "netsuite_sales_order_id": "netsuite_sales_order_id", - } - ], - add_recurring_commits=[ - { - "access_amount": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "unit_price": 0, - "quantity": 0, - }, - "commit_duration": { - "value": 0, - "unit": "PERIODS", - }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "description": "description", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "hierarchy_configuration": {"child_access": {"type": "ALL"}}, - "invoice_amount": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "quantity": 0, - "unit_price": 0, - }, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "proration": "NONE", - "rate_type": "COMMIT_RATE", - "recurrence_frequency": "MONTHLY", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - "subscription_config": { - "apply_seat_increase_config": {"is_prorated": True}, - "subscription_id": "subscription_id", - "allocation": "POOLED", - }, - "temporary_id": "temporary_id", - } - ], - add_recurring_credits=[ - { - "access_amount": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "unit_price": 0, - "quantity": 0, - }, - "commit_duration": { - "value": 0, - "unit": "PERIODS", - }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "description": "description", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "hierarchy_configuration": {"child_access": {"type": "ALL"}}, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "proration": "NONE", - "rate_type": "COMMIT_RATE", - "recurrence_frequency": "MONTHLY", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - "subscription_config": { - "apply_seat_increase_config": {"is_prorated": True}, - "subscription_id": "subscription_id", - "allocation": "POOLED", - }, - "temporary_id": "temporary_id", - } - ], - add_reseller_royalties=[ - { - "reseller_type": "AWS", - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "aws_options": { - "aws_account_number": "aws_account_number", - "aws_offer_id": "aws_offer_id", - "aws_payer_reference_id": "aws_payer_reference_id", - }, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "fraction": 0, - "gcp_options": { - "gcp_account_id": "gcp_account_id", - "gcp_offer_id": "gcp_offer_id", - }, - "netsuite_reseller_id": "netsuite_reseller_id", - "reseller_contract_value": 0, - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - add_revenue_system_configuration_update={ - "revenue_system_configuration": { - "delivery_method": "direct_to_billing_provider", - "provider": "netsuite", - "revenue_system_configuration_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "schedule": {"effective_at": "START_OF_CURRENT_PERIOD"}, - }, - add_scheduled_charges=[ - { - "product_id": "2e30f074-d04c-412e-a134-851ebfa5ceb2", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "do_not_invoice": True, - "recurring_schedule": { - "amount_distribution": "DIVIDED", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "frequency": "MONTHLY", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - "schedule_items": [ - { - "timestamp": parse_datetime("2020-02-15T00:00:00.000Z"), - "amount": 0, - "quantity": 1, - "unit_price": 1000000, - } - ], - }, - "custom_fields": {"foo": "string"}, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - } - ], - add_spend_threshold_configuration={ - "commit": { - "description": "description", - "name": "name", - "product_id": "product_id", - }, - "is_enabled": True, - "payment_gate_config": { - "payment_gate_type": "NONE", - "precalculated_tax_config": { - "tax_amount": 0, - "tax_name": "tax_name", - }, - "stripe_config": { - "payment_type": "INVOICE", - "invoice_metadata": {"foo": "string"}, - }, - "tax_type": "NONE", - }, - "threshold_amount": 0, - }, - add_subscriptions=[ - { - "collection_schedule": "ADVANCE", - "proration": { - "invoice_behavior": "BILL_IMMEDIATELY", - "is_prorated": True, - }, - "subscription_rate": { - "billing_frequency": "MONTHLY", - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "custom_fields": {"foo": "string"}, - "description": "description", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "initial_quantity": 0, - "name": "name", - "quantity_management_mode": "SEAT_BASED", - "seat_config": { - "initial_seat_ids": ["string"], - "seat_group_key": "seat_group_key", - "initial_unassigned_seats": 0, - }, - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "temporary_id": "temporary_id", - } - ], - allow_contract_ending_before_finalized_invoice=True, - archive_commits=[{"id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - archive_credits=[{"id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - archive_scheduled_charges=[{"id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - remove_overrides=[{"id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - uniqueness_key="x", - update_commits=[ - { - "commit_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "access_schedule": { - "add_schedule_items": [ - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "remove_schedule_items": [{"id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - "update_schedule_items": [ - { - "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - }, - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "description": "description", - "hierarchy_configuration": {"child_access": {"type": "ALL"}}, - "invoice_schedule": { - "add_schedule_items": [ - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - } - ], - "remove_schedule_items": [{"id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - "update_schedule_items": [ - { - "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "amount": 0, - "quantity": 0, - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "unit_price": 0, - } - ], - }, - "name": "name", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "rate_type": "LIST_RATE", - "rollover_fraction": 0, - } - ], - update_contract_end_date=parse_datetime("2019-12-27T18:11:19.117Z"), - update_contract_name="update_contract_name", - update_credits=[ - { - "credit_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "access_schedule": { - "add_schedule_items": [ - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "remove_schedule_items": [{"id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - "update_schedule_items": [ - { - "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - }, - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "description": "description", - "hierarchy_configuration": {"child_access": {"type": "ALL"}}, - "name": "name", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "rate_type": "LIST_RATE", - "rollover_fraction": 0, - } - ], - update_net_payment_terms_days=0, - update_prepaid_balance_threshold_configuration={ - "commit": { - "description": "description", - "name": "name", - "product_id": "product_id", - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - }, - "custom_credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "is_enabled": True, - "payment_gate_config": { - "payment_gate_type": "NONE", - "precalculated_tax_config": { - "tax_amount": 0, - "tax_name": "tax_name", - }, - "stripe_config": { - "payment_type": "INVOICE", - "invoice_metadata": {"foo": "string"}, - }, - "tax_type": "NONE", - }, - "recharge_to_amount": 0, - "threshold_amount": 0, - }, - update_recurring_commits=[ - { - "recurring_commit_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "access_amount": { - "quantity": 0, - "unit_price": 0, - }, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "invoice_amount": { - "quantity": 0, - "unit_price": 0, - }, - "rate_type": "LIST_RATE", - } - ], - update_recurring_credits=[ - { - "recurring_credit_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "access_amount": { - "quantity": 0, - "unit_price": 0, - }, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "rate_type": "LIST_RATE", - } - ], - update_scheduled_charges=[ - { - "scheduled_charge_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "invoice_schedule": { - "add_schedule_items": [ - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - } - ], - "remove_schedule_items": [{"id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - "update_schedule_items": [ - { - "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "amount": 0, - "quantity": 0, - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "unit_price": 0, - } - ], - }, - "netsuite_sales_order_id": "netsuite_sales_order_id", - } - ], - update_spend_threshold_configuration={ - "commit": { - "description": "description", - "name": "name", - "product_id": "product_id", - }, - "is_enabled": True, - "payment_gate_config": { - "payment_gate_type": "NONE", - "precalculated_tax_config": { - "tax_amount": 0, - "tax_name": "tax_name", - }, - "stripe_config": { - "payment_type": "INVOICE", - "invoice_metadata": {"foo": "string"}, - }, - "tax_type": "NONE", - }, - "threshold_amount": 0, - }, - update_subscriptions=[ - { - "subscription_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity_management_mode_update": { - "quantity_management_mode": "SEAT_BASED", - "seat_config": {"seat_group_key": "seat_group_key"}, - }, - "quantity_updates": [ - { - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 0, - "quantity_delta": 0, - } - ], - "seat_updates": { - "add_seat_ids": [ - { - "seat_ids": ["string"], - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "add_unassigned_seats": [ - { - "quantity": 1, - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "remove_seat_ids": [ - { - "seat_ids": ["string"], - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "remove_unassigned_seats": [ - { - "quantity": 1, - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - }, - } - ], - ) - assert_matches_type(ContractEditResponse, contract, path=["response"]) - - @parametrize - def test_raw_response_edit(self, client: Metronome) -> None: - response = client.v2.contracts.with_raw_response.edit( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = response.parse() - assert_matches_type(ContractEditResponse, contract, path=["response"]) - - @parametrize - def test_streaming_response_edit(self, client: Metronome) -> None: - with client.v2.contracts.with_streaming_response.edit( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = response.parse() - assert_matches_type(ContractEditResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_edit_commit(self, client: Metronome) -> None: - contract = client.v2.contracts.edit_commit( - commit_id="5e7e82cf-ccb7-428c-a96f-a8e4f67af822", - customer_id="4c91c473-fc12-445a-9c38-40421d47023f", - ) - assert_matches_type(ContractEditCommitResponse, contract, path=["response"]) - - @parametrize - def test_method_edit_commit_with_all_params(self, client: Metronome) -> None: - contract = client.v2.contracts.edit_commit( - commit_id="5e7e82cf-ccb7-428c-a96f-a8e4f67af822", - customer_id="4c91c473-fc12-445a-9c38-40421d47023f", - access_schedule={ - "add_schedule_items": [ - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "remove_schedule_items": [{"id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - "update_schedule_items": [ - { - "id": "d5edbd32-c744-48cb-9475-a9bca0e6fa39", - "amount": 0, - "ending_before": parse_datetime("2025-03-12T00:00:00Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - }, - applicable_product_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - applicable_product_tags=["string"], - description="description", - hierarchy_configuration={"child_access": {"type": "ALL"}}, - invoice_contract_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - invoice_schedule={ - "add_schedule_items": [ - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - } - ], - "remove_schedule_items": [{"id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - "update_schedule_items": [ - { - "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "amount": 0, - "quantity": 0, - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "unit_price": 0, - } - ], - }, - name="name", - priority=0, - product_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - rate_type="LIST_RATE", - specifiers=[ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - ) - assert_matches_type(ContractEditCommitResponse, contract, path=["response"]) - - @parametrize - def test_raw_response_edit_commit(self, client: Metronome) -> None: - response = client.v2.contracts.with_raw_response.edit_commit( - commit_id="5e7e82cf-ccb7-428c-a96f-a8e4f67af822", - customer_id="4c91c473-fc12-445a-9c38-40421d47023f", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = response.parse() - assert_matches_type(ContractEditCommitResponse, contract, path=["response"]) - - @parametrize - def test_streaming_response_edit_commit(self, client: Metronome) -> None: - with client.v2.contracts.with_streaming_response.edit_commit( - commit_id="5e7e82cf-ccb7-428c-a96f-a8e4f67af822", - customer_id="4c91c473-fc12-445a-9c38-40421d47023f", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = response.parse() - assert_matches_type(ContractEditCommitResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_edit_credit(self, client: Metronome) -> None: - contract = client.v2.contracts.edit_credit( - credit_id="5e7e82cf-ccb7-428c-a96f-a8e4f67af822", - customer_id="4c91c473-fc12-445a-9c38-40421d47023f", - ) - assert_matches_type(ContractEditCreditResponse, contract, path=["response"]) - - @parametrize - def test_method_edit_credit_with_all_params(self, client: Metronome) -> None: - contract = client.v2.contracts.edit_credit( - credit_id="5e7e82cf-ccb7-428c-a96f-a8e4f67af822", - customer_id="4c91c473-fc12-445a-9c38-40421d47023f", - access_schedule={ - "add_schedule_items": [ - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "remove_schedule_items": [{"id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - "update_schedule_items": [ - { - "id": "d5edbd32-c744-48cb-9475-a9bca0e6fa39", - "amount": 0, - "ending_before": parse_datetime("2025-03-12T00:00:00Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - }, - applicable_product_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - applicable_product_tags=["string"], - description="description", - hierarchy_configuration={"child_access": {"type": "ALL"}}, - name="name", - priority=0, - product_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - rate_type="LIST_RATE", - specifiers=[ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - ) - assert_matches_type(ContractEditCreditResponse, contract, path=["response"]) - - @parametrize - def test_raw_response_edit_credit(self, client: Metronome) -> None: - response = client.v2.contracts.with_raw_response.edit_credit( - credit_id="5e7e82cf-ccb7-428c-a96f-a8e4f67af822", - customer_id="4c91c473-fc12-445a-9c38-40421d47023f", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = response.parse() - assert_matches_type(ContractEditCreditResponse, contract, path=["response"]) - - @parametrize - def test_streaming_response_edit_credit(self, client: Metronome) -> None: - with client.v2.contracts.with_streaming_response.edit_credit( - credit_id="5e7e82cf-ccb7-428c-a96f-a8e4f67af822", - customer_id="4c91c473-fc12-445a-9c38-40421d47023f", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = response.parse() - assert_matches_type(ContractEditCreditResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - def test_method_get_edit_history(self, client: Metronome) -> None: - contract = client.v2.contracts.get_edit_history( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(ContractGetEditHistoryResponse, contract, path=["response"]) - - @parametrize - def test_raw_response_get_edit_history(self, client: Metronome) -> None: - response = client.v2.contracts.with_raw_response.get_edit_history( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = response.parse() - assert_matches_type(ContractGetEditHistoryResponse, contract, path=["response"]) - - @parametrize - def test_streaming_response_get_edit_history(self, client: Metronome) -> None: - with client.v2.contracts.with_streaming_response.get_edit_history( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = response.parse() - assert_matches_type(ContractGetEditHistoryResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - -class TestAsyncContracts: - parametrize = pytest.mark.parametrize( - "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] - ) - - @parametrize - async def test_method_retrieve(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v2.contracts.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(ContractRetrieveResponse, contract, path=["response"]) - - @parametrize - async def test_method_retrieve_with_all_params(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v2.contracts.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - as_of_date=parse_datetime("2019-12-27T18:11:19.117Z"), - include_balance=True, - include_ledgers=True, - ) - assert_matches_type(ContractRetrieveResponse, contract, path=["response"]) - - @parametrize - async def test_raw_response_retrieve(self, async_client: AsyncMetronome) -> None: - response = await async_client.v2.contracts.with_raw_response.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = await response.parse() - assert_matches_type(ContractRetrieveResponse, contract, path=["response"]) - - @parametrize - async def test_streaming_response_retrieve(self, async_client: AsyncMetronome) -> None: - async with async_client.v2.contracts.with_streaming_response.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = await response.parse() - assert_matches_type(ContractRetrieveResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_list(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v2.contracts.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(ContractListResponse, contract, path=["response"]) - - @parametrize - async def test_method_list_with_all_params(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v2.contracts.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - covering_date=parse_datetime("2019-12-27T18:11:19.117Z"), - include_archived=True, - include_balance=True, - include_ledgers=True, - starting_at=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(ContractListResponse, contract, path=["response"]) - - @parametrize - async def test_raw_response_list(self, async_client: AsyncMetronome) -> None: - response = await async_client.v2.contracts.with_raw_response.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = await response.parse() - assert_matches_type(ContractListResponse, contract, path=["response"]) - - @parametrize - async def test_streaming_response_list(self, async_client: AsyncMetronome) -> None: - async with async_client.v2.contracts.with_streaming_response.list( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = await response.parse() - assert_matches_type(ContractListResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_edit(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v2.contracts.edit( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(ContractEditResponse, contract, path=["response"]) - - @parametrize - async def test_method_edit_with_all_params(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v2.contracts.edit( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - add_billing_provider_configuration_update={ - "billing_provider_configuration": { - "billing_provider": "aws_marketplace", - "billing_provider_configuration_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "delivery_method": "direct_to_billing_provider", - }, - "schedule": {"effective_at": "START_OF_CURRENT_PERIOD"}, - }, - add_commits=[ - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "type": "PREPAID", - "access_schedule": { - "schedule_items": [ - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "amount": 0, - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "hierarchy_configuration": {"child_access": {"type": "ALL"}}, - "invoice_schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "do_not_invoice": True, - "recurring_schedule": { - "amount_distribution": "DIVIDED", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "frequency": "MONTHLY", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - "schedule_items": [ - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - } - ], - }, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "payment_gate_config": { - "payment_gate_type": "NONE", - "precalculated_tax_config": { - "tax_amount": 0, - "tax_name": "tax_name", - }, - "stripe_config": { - "payment_type": "INVOICE", - "invoice_metadata": {"foo": "string"}, - "on_session_payment": True, - }, - "tax_type": "NONE", - }, - "priority": 0, - "rate_type": "COMMIT_RATE", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - "temporary_id": "temporary_id", - } - ], - add_credits=[ - { - "access_schedule": { - "schedule_items": [ - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "hierarchy_configuration": {"child_access": {"type": "ALL"}}, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "priority": 0, - "rate_type": "COMMIT_RATE", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - } - ], - add_discounts=[ - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "do_not_invoice": True, - "recurring_schedule": { - "amount_distribution": "DIVIDED", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "frequency": "MONTHLY", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - "schedule_items": [ - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - } - ], - }, - "custom_fields": {"foo": "string"}, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - } - ], - add_overrides=[ - { - "starting_at": parse_datetime("2024-11-02T00:00:00Z"), - "applicable_product_tags": ["string"], - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "entitled": True, - "is_commit_specific": True, - "multiplier": 2, - "override_specifiers": [ - { - "billing_frequency": "MONTHLY", - "commit_ids": ["string"], - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - "recurring_commit_ids": ["string"], - "recurring_credit_ids": ["string"], - } - ], - "overwrite_rate": { - "rate_type": "FLAT", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "custom_rate": {"foo": "bar"}, - "is_prorated": True, - "price": 0, - "quantity": 0, - "tiers": [ - { - "price": 0, - "size": 0, - } - ], - }, - "priority": 100, - "product_id": "d4fc086c-d8e5-4091-a235-fbba5da4ec14", - "target": "COMMIT_RATE", - "tiers": [ - { - "multiplier": 0, - "size": 0, - } - ], - "type": "MULTIPLIER", - } - ], - add_prepaid_balance_threshold_configuration={ - "commit": { - "description": "description", - "name": "name", - "product_id": "product_id", - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - }, - "is_enabled": True, - "payment_gate_config": { - "payment_gate_type": "NONE", - "precalculated_tax_config": { - "tax_amount": 0, - "tax_name": "tax_name", - }, - "stripe_config": { - "payment_type": "INVOICE", - "invoice_metadata": {"foo": "string"}, - }, - "tax_type": "NONE", - }, - "recharge_to_amount": 0, - "threshold_amount": 0, - "custom_credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - add_professional_services=[ - { - "max_amount": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "quantity": 0, - "unit_price": 0, - "custom_fields": {"foo": "string"}, - "description": "description", - "netsuite_sales_order_id": "netsuite_sales_order_id", - } - ], - add_recurring_commits=[ - { - "access_amount": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "unit_price": 0, - "quantity": 0, - }, - "commit_duration": { - "value": 0, - "unit": "PERIODS", - }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "description": "description", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "hierarchy_configuration": {"child_access": {"type": "ALL"}}, - "invoice_amount": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "quantity": 0, - "unit_price": 0, - }, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "proration": "NONE", - "rate_type": "COMMIT_RATE", - "recurrence_frequency": "MONTHLY", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - "subscription_config": { - "apply_seat_increase_config": {"is_prorated": True}, - "subscription_id": "subscription_id", - "allocation": "POOLED", - }, - "temporary_id": "temporary_id", - } - ], - add_recurring_credits=[ - { - "access_amount": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "unit_price": 0, - "quantity": 0, - }, - "commit_duration": { - "value": 0, - "unit": "PERIODS", - }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "description": "description", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "hierarchy_configuration": {"child_access": {"type": "ALL"}}, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "proration": "NONE", - "rate_type": "COMMIT_RATE", - "recurrence_frequency": "MONTHLY", - "rollover_fraction": 0, - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - "subscription_config": { - "apply_seat_increase_config": {"is_prorated": True}, - "subscription_id": "subscription_id", - "allocation": "POOLED", - }, - "temporary_id": "temporary_id", - } - ], - add_reseller_royalties=[ - { - "reseller_type": "AWS", - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "aws_options": { - "aws_account_number": "aws_account_number", - "aws_offer_id": "aws_offer_id", - "aws_payer_reference_id": "aws_payer_reference_id", - }, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "fraction": 0, - "gcp_options": { - "gcp_account_id": "gcp_account_id", - "gcp_offer_id": "gcp_offer_id", - }, - "netsuite_reseller_id": "netsuite_reseller_id", - "reseller_contract_value": 0, - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - add_revenue_system_configuration_update={ - "revenue_system_configuration": { - "delivery_method": "direct_to_billing_provider", - "provider": "netsuite", - "revenue_system_configuration_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "schedule": {"effective_at": "START_OF_CURRENT_PERIOD"}, - }, - add_scheduled_charges=[ - { - "product_id": "2e30f074-d04c-412e-a134-851ebfa5ceb2", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "do_not_invoice": True, - "recurring_schedule": { - "amount_distribution": "DIVIDED", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "frequency": "MONTHLY", - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - "schedule_items": [ - { - "timestamp": parse_datetime("2020-02-15T00:00:00.000Z"), - "amount": 0, - "quantity": 1, - "unit_price": 1000000, - } - ], - }, - "custom_fields": {"foo": "string"}, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - } - ], - add_spend_threshold_configuration={ - "commit": { - "description": "description", - "name": "name", - "product_id": "product_id", - }, - "is_enabled": True, - "payment_gate_config": { - "payment_gate_type": "NONE", - "precalculated_tax_config": { - "tax_amount": 0, - "tax_name": "tax_name", - }, - "stripe_config": { - "payment_type": "INVOICE", - "invoice_metadata": {"foo": "string"}, - }, - "tax_type": "NONE", - }, - "threshold_amount": 0, - }, - add_subscriptions=[ - { - "collection_schedule": "ADVANCE", - "proration": { - "invoice_behavior": "BILL_IMMEDIATELY", - "is_prorated": True, - }, - "subscription_rate": { - "billing_frequency": "MONTHLY", - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - "custom_fields": {"foo": "string"}, - "description": "description", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "initial_quantity": 0, - "name": "name", - "quantity_management_mode": "SEAT_BASED", - "seat_config": { - "initial_seat_ids": ["string"], - "seat_group_key": "seat_group_key", - "initial_unassigned_seats": 0, - }, - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "temporary_id": "temporary_id", - } - ], - allow_contract_ending_before_finalized_invoice=True, - archive_commits=[{"id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - archive_credits=[{"id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - archive_scheduled_charges=[{"id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - remove_overrides=[{"id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - uniqueness_key="x", - update_commits=[ - { - "commit_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "access_schedule": { - "add_schedule_items": [ - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "remove_schedule_items": [{"id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - "update_schedule_items": [ - { - "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - }, - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "description": "description", - "hierarchy_configuration": {"child_access": {"type": "ALL"}}, - "invoice_schedule": { - "add_schedule_items": [ - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - } - ], - "remove_schedule_items": [{"id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - "update_schedule_items": [ - { - "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "amount": 0, - "quantity": 0, - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "unit_price": 0, - } - ], - }, - "name": "name", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "rate_type": "LIST_RATE", - "rollover_fraction": 0, - } - ], - update_contract_end_date=parse_datetime("2019-12-27T18:11:19.117Z"), - update_contract_name="update_contract_name", - update_credits=[ - { - "credit_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "access_schedule": { - "add_schedule_items": [ - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "remove_schedule_items": [{"id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - "update_schedule_items": [ - { - "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - }, - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "description": "description", - "hierarchy_configuration": {"child_access": {"type": "ALL"}}, - "name": "name", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "rate_type": "LIST_RATE", - "rollover_fraction": 0, - } - ], - update_net_payment_terms_days=0, - update_prepaid_balance_threshold_configuration={ - "commit": { - "description": "description", - "name": "name", - "product_id": "product_id", - "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - "applicable_product_tags": ["string"], - "specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - }, - "custom_credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "is_enabled": True, - "payment_gate_config": { - "payment_gate_type": "NONE", - "precalculated_tax_config": { - "tax_amount": 0, - "tax_name": "tax_name", - }, - "stripe_config": { - "payment_type": "INVOICE", - "invoice_metadata": {"foo": "string"}, - }, - "tax_type": "NONE", - }, - "recharge_to_amount": 0, - "threshold_amount": 0, - }, - update_recurring_commits=[ - { - "recurring_commit_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "access_amount": { - "quantity": 0, - "unit_price": 0, - }, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "invoice_amount": { - "quantity": 0, - "unit_price": 0, - }, - "rate_type": "LIST_RATE", - } - ], - update_recurring_credits=[ - { - "recurring_credit_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "access_amount": { - "quantity": 0, - "unit_price": 0, - }, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "rate_type": "LIST_RATE", - } - ], - update_scheduled_charges=[ - { - "scheduled_charge_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "invoice_schedule": { - "add_schedule_items": [ - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - } - ], - "remove_schedule_items": [{"id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - "update_schedule_items": [ - { - "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "amount": 0, - "quantity": 0, - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "unit_price": 0, - } - ], - }, - "netsuite_sales_order_id": "netsuite_sales_order_id", - } - ], - update_spend_threshold_configuration={ - "commit": { - "description": "description", - "name": "name", - "product_id": "product_id", - }, - "is_enabled": True, - "payment_gate_config": { - "payment_gate_type": "NONE", - "precalculated_tax_config": { - "tax_amount": 0, - "tax_name": "tax_name", - }, - "stripe_config": { - "payment_type": "INVOICE", - "invoice_metadata": {"foo": "string"}, - }, - "tax_type": "NONE", - }, - "threshold_amount": 0, - }, - update_subscriptions=[ - { - "subscription_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity_management_mode_update": { - "quantity_management_mode": "SEAT_BASED", - "seat_config": {"seat_group_key": "seat_group_key"}, - }, - "quantity_updates": [ - { - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "quantity": 0, - "quantity_delta": 0, - } - ], - "seat_updates": { - "add_seat_ids": [ - { - "seat_ids": ["string"], - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "add_unassigned_seats": [ - { - "quantity": 1, - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "remove_seat_ids": [ - { - "seat_ids": ["string"], - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "remove_unassigned_seats": [ - { - "quantity": 1, - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - }, - } - ], - ) - assert_matches_type(ContractEditResponse, contract, path=["response"]) - - @parametrize - async def test_raw_response_edit(self, async_client: AsyncMetronome) -> None: - response = await async_client.v2.contracts.with_raw_response.edit( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = await response.parse() - assert_matches_type(ContractEditResponse, contract, path=["response"]) - - @parametrize - async def test_streaming_response_edit(self, async_client: AsyncMetronome) -> None: - async with async_client.v2.contracts.with_streaming_response.edit( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = await response.parse() - assert_matches_type(ContractEditResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_edit_commit(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v2.contracts.edit_commit( - commit_id="5e7e82cf-ccb7-428c-a96f-a8e4f67af822", - customer_id="4c91c473-fc12-445a-9c38-40421d47023f", - ) - assert_matches_type(ContractEditCommitResponse, contract, path=["response"]) - - @parametrize - async def test_method_edit_commit_with_all_params(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v2.contracts.edit_commit( - commit_id="5e7e82cf-ccb7-428c-a96f-a8e4f67af822", - customer_id="4c91c473-fc12-445a-9c38-40421d47023f", - access_schedule={ - "add_schedule_items": [ - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "remove_schedule_items": [{"id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - "update_schedule_items": [ - { - "id": "d5edbd32-c744-48cb-9475-a9bca0e6fa39", - "amount": 0, - "ending_before": parse_datetime("2025-03-12T00:00:00Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - }, - applicable_product_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - applicable_product_tags=["string"], - description="description", - hierarchy_configuration={"child_access": {"type": "ALL"}}, - invoice_contract_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - invoice_schedule={ - "add_schedule_items": [ - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - } - ], - "remove_schedule_items": [{"id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - "update_schedule_items": [ - { - "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "amount": 0, - "quantity": 0, - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "unit_price": 0, - } - ], - }, - name="name", - priority=0, - product_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - rate_type="LIST_RATE", - specifiers=[ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - ) - assert_matches_type(ContractEditCommitResponse, contract, path=["response"]) - - @parametrize - async def test_raw_response_edit_commit(self, async_client: AsyncMetronome) -> None: - response = await async_client.v2.contracts.with_raw_response.edit_commit( - commit_id="5e7e82cf-ccb7-428c-a96f-a8e4f67af822", - customer_id="4c91c473-fc12-445a-9c38-40421d47023f", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = await response.parse() - assert_matches_type(ContractEditCommitResponse, contract, path=["response"]) - - @parametrize - async def test_streaming_response_edit_commit(self, async_client: AsyncMetronome) -> None: - async with async_client.v2.contracts.with_streaming_response.edit_commit( - commit_id="5e7e82cf-ccb7-428c-a96f-a8e4f67af822", - customer_id="4c91c473-fc12-445a-9c38-40421d47023f", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = await response.parse() - assert_matches_type(ContractEditCommitResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_edit_credit(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v2.contracts.edit_credit( - credit_id="5e7e82cf-ccb7-428c-a96f-a8e4f67af822", - customer_id="4c91c473-fc12-445a-9c38-40421d47023f", - ) - assert_matches_type(ContractEditCreditResponse, contract, path=["response"]) - - @parametrize - async def test_method_edit_credit_with_all_params(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v2.contracts.edit_credit( - credit_id="5e7e82cf-ccb7-428c-a96f-a8e4f67af822", - customer_id="4c91c473-fc12-445a-9c38-40421d47023f", - access_schedule={ - "add_schedule_items": [ - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - "remove_schedule_items": [{"id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], - "update_schedule_items": [ - { - "id": "d5edbd32-c744-48cb-9475-a9bca0e6fa39", - "amount": 0, - "ending_before": parse_datetime("2025-03-12T00:00:00Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - } - ], - }, - applicable_product_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], - applicable_product_tags=["string"], - description="description", - hierarchy_configuration={"child_access": {"type": "ALL"}}, - name="name", - priority=0, - product_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - rate_type="LIST_RATE", - specifiers=[ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string"], - } - ], - ) - assert_matches_type(ContractEditCreditResponse, contract, path=["response"]) - - @parametrize - async def test_raw_response_edit_credit(self, async_client: AsyncMetronome) -> None: - response = await async_client.v2.contracts.with_raw_response.edit_credit( - credit_id="5e7e82cf-ccb7-428c-a96f-a8e4f67af822", - customer_id="4c91c473-fc12-445a-9c38-40421d47023f", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = await response.parse() - assert_matches_type(ContractEditCreditResponse, contract, path=["response"]) - - @parametrize - async def test_streaming_response_edit_credit(self, async_client: AsyncMetronome) -> None: - async with async_client.v2.contracts.with_streaming_response.edit_credit( - credit_id="5e7e82cf-ccb7-428c-a96f-a8e4f67af822", - customer_id="4c91c473-fc12-445a-9c38-40421d47023f", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = await response.parse() - assert_matches_type(ContractEditCreditResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True - - @parametrize - async def test_method_get_edit_history(self, async_client: AsyncMetronome) -> None: - contract = await async_client.v2.contracts.get_edit_history( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(ContractGetEditHistoryResponse, contract, path=["response"]) - - @parametrize - async def test_raw_response_get_edit_history(self, async_client: AsyncMetronome) -> None: - response = await async_client.v2.contracts.with_raw_response.get_edit_history( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - - assert response.is_closed is True - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - contract = await response.parse() - assert_matches_type(ContractGetEditHistoryResponse, contract, path=["response"]) - - @parametrize - async def test_streaming_response_get_edit_history(self, async_client: AsyncMetronome) -> None: - async with async_client.v2.contracts.with_streaming_response.get_edit_history( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) as response: - assert not response.is_closed - assert response.http_request.headers.get("X-Stainless-Lang") == "python" - - contract = await response.parse() - assert_matches_type(ContractGetEditHistoryResponse, contract, path=["response"]) - - assert cast(Any, response.is_closed) is True diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index 1f205b409..000000000 --- a/tests/conftest.py +++ /dev/null @@ -1,84 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -import logging -from typing import TYPE_CHECKING, Iterator, AsyncIterator - -import httpx -import pytest -from pytest_asyncio import is_async_test - -from metronome import Metronome, AsyncMetronome, DefaultAioHttpClient -from metronome._utils import is_dict - -if TYPE_CHECKING: - from _pytest.fixtures import FixtureRequest # pyright: ignore[reportPrivateImportUsage] - -pytest.register_assert_rewrite("tests.utils") - -logging.getLogger("metronome").setLevel(logging.DEBUG) - - -# automatically add `pytest.mark.asyncio()` to all of our async tests -# so we don't have to add that boilerplate everywhere -def pytest_collection_modifyitems(items: list[pytest.Function]) -> None: - pytest_asyncio_tests = (item for item in items if is_async_test(item)) - session_scope_marker = pytest.mark.asyncio(loop_scope="session") - for async_test in pytest_asyncio_tests: - async_test.add_marker(session_scope_marker, append=False) - - # We skip tests that use both the aiohttp client and respx_mock as respx_mock - # doesn't support custom transports. - for item in items: - if "async_client" not in item.fixturenames or "respx_mock" not in item.fixturenames: - continue - - if not hasattr(item, "callspec"): - continue - - async_client_param = item.callspec.params.get("async_client") - if is_dict(async_client_param) and async_client_param.get("http_client") == "aiohttp": - item.add_marker(pytest.mark.skip(reason="aiohttp client is not compatible with respx_mock")) - - -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") - -bearer_token = "My Bearer Token" - - -@pytest.fixture(scope="session") -def client(request: FixtureRequest) -> Iterator[Metronome]: - strict = getattr(request, "param", True) - if not isinstance(strict, bool): - raise TypeError(f"Unexpected fixture parameter type {type(strict)}, expected {bool}") - - with Metronome(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=strict) as client: - yield client - - -@pytest.fixture(scope="session") -async def async_client(request: FixtureRequest) -> AsyncIterator[AsyncMetronome]: - param = getattr(request, "param", True) - - # defaults - strict = True - http_client: None | httpx.AsyncClient = None - - if isinstance(param, bool): - strict = param - elif is_dict(param): - strict = param.get("strict", True) - assert isinstance(strict, bool) - - http_client_type = param.get("http_client", "httpx") - if http_client_type == "aiohttp": - http_client = DefaultAioHttpClient() - else: - raise TypeError(f"Unexpected fixture parameter type {type(param)}, expected bool or dict") - - async with AsyncMetronome( - base_url=base_url, bearer_token=bearer_token, _strict_response_validation=strict, http_client=http_client - ) as client: - yield client diff --git a/tests/sample_file.txt b/tests/sample_file.txt deleted file mode 100644 index af5626b4a..000000000 --- a/tests/sample_file.txt +++ /dev/null @@ -1 +0,0 @@ -Hello, world! diff --git a/tests/test_client.py b/tests/test_client.py deleted file mode 100644 index af8d6470c..000000000 --- a/tests/test_client.py +++ /dev/null @@ -1,1996 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import gc -import os -import sys -import json -import asyncio -import inspect -import dataclasses -import tracemalloc -from typing import Any, Union, TypeVar, Callable, Iterable, Iterator, Optional, Coroutine, cast -from unittest import mock -from typing_extensions import Literal, AsyncIterator, override - -import httpx -import pytest -from respx import MockRouter -from pydantic import ValidationError - -from metronome import Metronome, AsyncMetronome, APIResponseValidationError -from metronome._types import Omit -from metronome._utils import asyncify, parse_datetime -from metronome._models import BaseModel, FinalRequestOptions -from metronome._exceptions import APIStatusError, MetronomeError, APITimeoutError, APIResponseValidationError -from metronome._base_client import ( - DEFAULT_TIMEOUT, - HTTPX_DEFAULT_TIMEOUT, - BaseClient, - OtherPlatform, - DefaultHttpxClient, - DefaultAsyncHttpxClient, - get_platform, - make_request_options, -) - -from .utils import update_env - -T = TypeVar("T") -base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") -bearer_token = "My Bearer Token" - - -def _get_params(client: BaseClient[Any, Any]) -> dict[str, str]: - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) - url = httpx.URL(request.url) - return dict(url.params) - - -def _low_retry_timeout(*_args: Any, **_kwargs: Any) -> float: - return 0.1 - - -def mirror_request_content(request: httpx.Request) -> httpx.Response: - return httpx.Response(200, content=request.content) - - -# note: we can't use the httpx.MockTransport class as it consumes the request -# body itself, which means we can't test that the body is read lazily -class MockTransport(httpx.BaseTransport, httpx.AsyncBaseTransport): - def __init__( - self, - handler: Callable[[httpx.Request], httpx.Response] - | Callable[[httpx.Request], Coroutine[Any, Any, httpx.Response]], - ) -> None: - self.handler = handler - - @override - def handle_request( - self, - request: httpx.Request, - ) -> httpx.Response: - assert not inspect.iscoroutinefunction(self.handler), "handler must not be a coroutine function" - assert inspect.isfunction(self.handler), "handler must be a function" - return self.handler(request) - - @override - async def handle_async_request( - self, - request: httpx.Request, - ) -> httpx.Response: - assert inspect.iscoroutinefunction(self.handler), "handler must be a coroutine function" - return await self.handler(request) - - -@dataclasses.dataclass -class Counter: - value: int = 0 - - -def _make_sync_iterator(iterable: Iterable[T], counter: Optional[Counter] = None) -> Iterator[T]: - for item in iterable: - if counter: - counter.value += 1 - yield item - - -async def _make_async_iterator(iterable: Iterable[T], counter: Optional[Counter] = None) -> AsyncIterator[T]: - for item in iterable: - if counter: - counter.value += 1 - yield item - - -def _get_open_connections(client: Metronome | AsyncMetronome) -> int: - transport = client._client._transport - assert isinstance(transport, httpx.HTTPTransport) or isinstance(transport, httpx.AsyncHTTPTransport) - - pool = transport._pool - return len(pool._requests) - - -class TestMetronome: - @pytest.mark.respx(base_url=base_url) - def test_raw_response(self, respx_mock: MockRouter, client: Metronome) -> None: - respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - - response = client.post("/foo", cast_to=httpx.Response) - assert response.status_code == 200 - assert isinstance(response, httpx.Response) - assert response.json() == {"foo": "bar"} - - @pytest.mark.respx(base_url=base_url) - def test_raw_response_for_binary(self, respx_mock: MockRouter, client: Metronome) -> None: - respx_mock.post("/foo").mock( - return_value=httpx.Response(200, headers={"Content-Type": "application/binary"}, content='{"foo": "bar"}') - ) - - response = client.post("/foo", cast_to=httpx.Response) - assert response.status_code == 200 - assert isinstance(response, httpx.Response) - assert response.json() == {"foo": "bar"} - - def test_copy(self, client: Metronome) -> None: - copied = client.copy() - assert id(copied) != id(client) - - copied = client.copy(bearer_token="another My Bearer Token") - assert copied.bearer_token == "another My Bearer Token" - assert client.bearer_token == "My Bearer Token" - - def test_copy_default_options(self, client: Metronome) -> None: - # options that have a default are overridden correctly - copied = client.copy(max_retries=7) - assert copied.max_retries == 7 - assert client.max_retries == 2 - - copied2 = copied.copy(max_retries=6) - assert copied2.max_retries == 6 - assert copied.max_retries == 7 - - # timeout - assert isinstance(client.timeout, httpx.Timeout) - copied = client.copy(timeout=None) - assert copied.timeout is None - assert isinstance(client.timeout, httpx.Timeout) - - def test_copy_default_headers(self) -> None: - client = Metronome( - base_url=base_url, - bearer_token=bearer_token, - _strict_response_validation=True, - default_headers={"X-Foo": "bar"}, - ) - assert client.default_headers["X-Foo"] == "bar" - - # does not override the already given value when not specified - copied = client.copy() - assert copied.default_headers["X-Foo"] == "bar" - - # merges already given headers - copied = client.copy(default_headers={"X-Bar": "stainless"}) - assert copied.default_headers["X-Foo"] == "bar" - assert copied.default_headers["X-Bar"] == "stainless" - - # uses new values for any already given headers - copied = client.copy(default_headers={"X-Foo": "stainless"}) - assert copied.default_headers["X-Foo"] == "stainless" - - # set_default_headers - - # completely overrides already set values - copied = client.copy(set_default_headers={}) - assert copied.default_headers.get("X-Foo") is None - - copied = client.copy(set_default_headers={"X-Bar": "Robert"}) - assert copied.default_headers["X-Bar"] == "Robert" - - with pytest.raises( - ValueError, - match="`default_headers` and `set_default_headers` arguments are mutually exclusive", - ): - client.copy(set_default_headers={}, default_headers={"X-Foo": "Bar"}) - client.close() - - def test_copy_default_query(self) -> None: - client = Metronome( - base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True, default_query={"foo": "bar"} - ) - assert _get_params(client)["foo"] == "bar" - - # does not override the already given value when not specified - copied = client.copy() - assert _get_params(copied)["foo"] == "bar" - - # merges already given params - copied = client.copy(default_query={"bar": "stainless"}) - params = _get_params(copied) - assert params["foo"] == "bar" - assert params["bar"] == "stainless" - - # uses new values for any already given headers - copied = client.copy(default_query={"foo": "stainless"}) - assert _get_params(copied)["foo"] == "stainless" - - # set_default_query - - # completely overrides already set values - copied = client.copy(set_default_query={}) - assert _get_params(copied) == {} - - copied = client.copy(set_default_query={"bar": "Robert"}) - assert _get_params(copied)["bar"] == "Robert" - - with pytest.raises( - ValueError, - # TODO: update - match="`default_query` and `set_default_query` arguments are mutually exclusive", - ): - client.copy(set_default_query={}, default_query={"foo": "Bar"}) - - client.close() - - def test_copy_signature(self, client: Metronome) -> None: - # ensure the same parameters that can be passed to the client are defined in the `.copy()` method - init_signature = inspect.signature( - # mypy doesn't like that we access the `__init__` property. - client.__init__, # type: ignore[misc] - ) - copy_signature = inspect.signature(client.copy) - exclude_params = {"transport", "proxies", "_strict_response_validation"} - - for name in init_signature.parameters.keys(): - if name in exclude_params: - continue - - copy_param = copy_signature.parameters.get(name) - assert copy_param is not None, f"copy() signature is missing the {name} param" - - @pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12") - def test_copy_build_request(self, client: Metronome) -> None: - options = FinalRequestOptions(method="get", url="/foo") - - def build_request(options: FinalRequestOptions) -> None: - client_copy = client.copy() - client_copy._build_request(options) - - # ensure that the machinery is warmed up before tracing starts. - build_request(options) - gc.collect() - - tracemalloc.start(1000) - - snapshot_before = tracemalloc.take_snapshot() - - ITERATIONS = 10 - for _ in range(ITERATIONS): - build_request(options) - - gc.collect() - snapshot_after = tracemalloc.take_snapshot() - - tracemalloc.stop() - - def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.StatisticDiff) -> None: - if diff.count == 0: - # Avoid false positives by considering only leaks (i.e. allocations that persist). - return - - if diff.count % ITERATIONS != 0: - # Avoid false positives by considering only leaks that appear per iteration. - return - - for frame in diff.traceback: - if any( - frame.filename.endswith(fragment) - for fragment in [ - # to_raw_response_wrapper leaks through the @functools.wraps() decorator. - # - # removing the decorator fixes the leak for reasons we don't understand. - "metronome/_legacy_response.py", - "metronome/_response.py", - # pydantic.BaseModel.model_dump || pydantic.BaseModel.dict leak memory for some reason. - "metronome/_compat.py", - # Standard library leaks we don't care about. - "/logging/__init__.py", - ] - ): - return - - leaks.append(diff) - - leaks: list[tracemalloc.StatisticDiff] = [] - for diff in snapshot_after.compare_to(snapshot_before, "traceback"): - add_leak(leaks, diff) - if leaks: - for leak in leaks: - print("MEMORY LEAK:", leak) - for frame in leak.traceback: - print(frame) - raise AssertionError() - - def test_request_timeout(self, client: Metronome) -> None: - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) - timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore - assert timeout == DEFAULT_TIMEOUT - - request = client._build_request(FinalRequestOptions(method="get", url="/foo", timeout=httpx.Timeout(100.0))) - timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore - assert timeout == httpx.Timeout(100.0) - - def test_client_timeout_option(self) -> None: - client = Metronome( - base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True, timeout=httpx.Timeout(0) - ) - - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) - timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore - assert timeout == httpx.Timeout(0) - - client.close() - - def test_http_client_timeout_option(self) -> None: - # custom timeout given to the httpx client should be used - with httpx.Client(timeout=None) as http_client: - client = Metronome( - base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True, http_client=http_client - ) - - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) - timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore - assert timeout == httpx.Timeout(None) - - client.close() - - # no timeout given to the httpx client should not use the httpx default - with httpx.Client() as http_client: - client = Metronome( - base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True, http_client=http_client - ) - - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) - timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore - assert timeout == DEFAULT_TIMEOUT - - client.close() - - # explicitly passing the default timeout currently results in it being ignored - with httpx.Client(timeout=HTTPX_DEFAULT_TIMEOUT) as http_client: - client = Metronome( - base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True, http_client=http_client - ) - - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) - timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore - assert timeout == DEFAULT_TIMEOUT # our default - - client.close() - - async def test_invalid_http_client(self) -> None: - with pytest.raises(TypeError, match="Invalid `http_client` arg"): - async with httpx.AsyncClient() as http_client: - Metronome( - base_url=base_url, - bearer_token=bearer_token, - _strict_response_validation=True, - http_client=cast(Any, http_client), - ) - - def test_default_headers_option(self) -> None: - test_client = Metronome( - base_url=base_url, - bearer_token=bearer_token, - _strict_response_validation=True, - default_headers={"X-Foo": "bar"}, - ) - request = test_client._build_request(FinalRequestOptions(method="get", url="/foo")) - assert request.headers.get("x-foo") == "bar" - assert request.headers.get("x-stainless-lang") == "python" - - test_client2 = Metronome( - base_url=base_url, - bearer_token=bearer_token, - _strict_response_validation=True, - default_headers={ - "X-Foo": "stainless", - "X-Stainless-Lang": "my-overriding-header", - }, - ) - request = test_client2._build_request(FinalRequestOptions(method="get", url="/foo")) - assert request.headers.get("x-foo") == "stainless" - assert request.headers.get("x-stainless-lang") == "my-overriding-header" - - test_client.close() - test_client2.close() - - def test_validate_headers(self) -> None: - client = Metronome(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True) - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) - assert request.headers.get("Authorization") == f"Bearer {bearer_token}" - - with pytest.raises(MetronomeError): - with update_env(**{"METRONOME_BEARER_TOKEN": Omit()}): - client2 = Metronome(base_url=base_url, bearer_token=None, _strict_response_validation=True) - _ = client2 - - def test_default_query_option(self) -> None: - client = Metronome( - base_url=base_url, - bearer_token=bearer_token, - _strict_response_validation=True, - default_query={"query_param": "bar"}, - ) - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) - url = httpx.URL(request.url) - assert dict(url.params) == {"query_param": "bar"} - - request = client._build_request( - FinalRequestOptions( - method="get", - url="/foo", - params={"foo": "baz", "query_param": "overridden"}, - ) - ) - url = httpx.URL(request.url) - assert dict(url.params) == {"foo": "baz", "query_param": "overridden"} - - client.close() - - def test_request_extra_json(self, client: Metronome) -> None: - request = client._build_request( - FinalRequestOptions( - method="post", - url="/foo", - json_data={"foo": "bar"}, - extra_json={"baz": False}, - ), - ) - data = json.loads(request.content.decode("utf-8")) - assert data == {"foo": "bar", "baz": False} - - request = client._build_request( - FinalRequestOptions( - method="post", - url="/foo", - extra_json={"baz": False}, - ), - ) - data = json.loads(request.content.decode("utf-8")) - assert data == {"baz": False} - - # `extra_json` takes priority over `json_data` when keys clash - request = client._build_request( - FinalRequestOptions( - method="post", - url="/foo", - json_data={"foo": "bar", "baz": True}, - extra_json={"baz": None}, - ), - ) - data = json.loads(request.content.decode("utf-8")) - assert data == {"foo": "bar", "baz": None} - - def test_request_extra_headers(self, client: Metronome) -> None: - request = client._build_request( - FinalRequestOptions( - method="post", - url="/foo", - **make_request_options(extra_headers={"X-Foo": "Foo"}), - ), - ) - assert request.headers.get("X-Foo") == "Foo" - - # `extra_headers` takes priority over `default_headers` when keys clash - request = client.with_options(default_headers={"X-Bar": "true"})._build_request( - FinalRequestOptions( - method="post", - url="/foo", - **make_request_options( - extra_headers={"X-Bar": "false"}, - ), - ), - ) - assert request.headers.get("X-Bar") == "false" - - def test_request_extra_query(self, client: Metronome) -> None: - request = client._build_request( - FinalRequestOptions( - method="post", - url="/foo", - **make_request_options( - extra_query={"my_query_param": "Foo"}, - ), - ), - ) - params = dict(request.url.params) - assert params == {"my_query_param": "Foo"} - - # if both `query` and `extra_query` are given, they are merged - request = client._build_request( - FinalRequestOptions( - method="post", - url="/foo", - **make_request_options( - query={"bar": "1"}, - extra_query={"foo": "2"}, - ), - ), - ) - params = dict(request.url.params) - assert params == {"bar": "1", "foo": "2"} - - # `extra_query` takes priority over `query` when keys clash - request = client._build_request( - FinalRequestOptions( - method="post", - url="/foo", - **make_request_options( - query={"foo": "1"}, - extra_query={"foo": "2"}, - ), - ), - ) - params = dict(request.url.params) - assert params == {"foo": "2"} - - def test_multipart_repeating_array(self, client: Metronome) -> None: - request = client._build_request( - FinalRequestOptions.construct( - method="post", - url="/foo", - headers={"Content-Type": "multipart/form-data; boundary=6b7ba517decee4a450543ea6ae821c82"}, - json_data={"array": ["foo", "bar"]}, - files=[("foo.txt", b"hello world")], - ) - ) - - assert request.read().split(b"\r\n") == [ - b"--6b7ba517decee4a450543ea6ae821c82", - b'Content-Disposition: form-data; name="array[]"', - b"", - b"foo", - b"--6b7ba517decee4a450543ea6ae821c82", - b'Content-Disposition: form-data; name="array[]"', - b"", - b"bar", - b"--6b7ba517decee4a450543ea6ae821c82", - b'Content-Disposition: form-data; name="foo.txt"; filename="upload"', - b"Content-Type: application/octet-stream", - b"", - b"hello world", - b"--6b7ba517decee4a450543ea6ae821c82--", - b"", - ] - - @pytest.mark.respx(base_url=base_url) - def test_binary_content_upload(self, respx_mock: MockRouter, client: Metronome) -> None: - respx_mock.post("/upload").mock(side_effect=mirror_request_content) - - file_content = b"Hello, this is a test file." - - response = client.post( - "/upload", - content=file_content, - cast_to=httpx.Response, - options={"headers": {"Content-Type": "application/octet-stream"}}, - ) - - assert response.status_code == 200 - assert response.request.headers["Content-Type"] == "application/octet-stream" - assert response.content == file_content - - def test_binary_content_upload_with_iterator(self) -> None: - file_content = b"Hello, this is a test file." - counter = Counter() - iterator = _make_sync_iterator([file_content], counter=counter) - - def mock_handler(request: httpx.Request) -> httpx.Response: - assert counter.value == 0, "the request body should not have been read" - return httpx.Response(200, content=request.read()) - - with Metronome( - base_url=base_url, - bearer_token=bearer_token, - _strict_response_validation=True, - http_client=httpx.Client(transport=MockTransport(handler=mock_handler)), - ) as client: - response = client.post( - "/upload", - content=iterator, - cast_to=httpx.Response, - options={"headers": {"Content-Type": "application/octet-stream"}}, - ) - - assert response.status_code == 200 - assert response.request.headers["Content-Type"] == "application/octet-stream" - assert response.content == file_content - assert counter.value == 1 - - @pytest.mark.respx(base_url=base_url) - def test_binary_content_upload_with_body_is_deprecated(self, respx_mock: MockRouter, client: Metronome) -> None: - respx_mock.post("/upload").mock(side_effect=mirror_request_content) - - file_content = b"Hello, this is a test file." - - with pytest.deprecated_call( - match="Passing raw bytes as `body` is deprecated and will be removed in a future version. Please pass raw bytes via the `content` parameter instead." - ): - response = client.post( - "/upload", - body=file_content, - cast_to=httpx.Response, - options={"headers": {"Content-Type": "application/octet-stream"}}, - ) - - assert response.status_code == 200 - assert response.request.headers["Content-Type"] == "application/octet-stream" - assert response.content == file_content - - @pytest.mark.respx(base_url=base_url) - def test_basic_union_response(self, respx_mock: MockRouter, client: Metronome) -> None: - class Model1(BaseModel): - name: str - - class Model2(BaseModel): - foo: str - - respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - - response = client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) - assert isinstance(response, Model2) - assert response.foo == "bar" - - @pytest.mark.respx(base_url=base_url) - def test_union_response_different_types(self, respx_mock: MockRouter, client: Metronome) -> None: - """Union of objects with the same field name using a different type""" - - class Model1(BaseModel): - foo: int - - class Model2(BaseModel): - foo: str - - respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - - response = client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) - assert isinstance(response, Model2) - assert response.foo == "bar" - - respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": 1})) - - response = client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) - assert isinstance(response, Model1) - assert response.foo == 1 - - @pytest.mark.respx(base_url=base_url) - def test_non_application_json_content_type_for_json_data(self, respx_mock: MockRouter, client: Metronome) -> None: - """ - Response that sets Content-Type to something other than application/json but returns json data - """ - - class Model(BaseModel): - foo: int - - respx_mock.get("/foo").mock( - return_value=httpx.Response( - 200, - content=json.dumps({"foo": 2}), - headers={"Content-Type": "application/text"}, - ) - ) - - response = client.get("/foo", cast_to=Model) - assert isinstance(response, Model) - assert response.foo == 2 - - def test_base_url_setter(self) -> None: - client = Metronome( - base_url="https://example.com/from_init", bearer_token=bearer_token, _strict_response_validation=True - ) - assert client.base_url == "https://example.com/from_init/" - - client.base_url = "https://example.com/from_setter" # type: ignore[assignment] - - assert client.base_url == "https://example.com/from_setter/" - - client.close() - - def test_base_url_env(self) -> None: - with update_env(METRONOME_BASE_URL="http://localhost:5000/from/env"): - client = Metronome(bearer_token=bearer_token, _strict_response_validation=True) - assert client.base_url == "http://localhost:5000/from/env/" - - @pytest.mark.parametrize( - "client", - [ - Metronome( - base_url="http://localhost:5000/custom/path/", - bearer_token=bearer_token, - _strict_response_validation=True, - ), - Metronome( - base_url="http://localhost:5000/custom/path/", - bearer_token=bearer_token, - _strict_response_validation=True, - http_client=httpx.Client(), - ), - ], - ids=["standard", "custom http client"], - ) - def test_base_url_trailing_slash(self, client: Metronome) -> None: - request = client._build_request( - FinalRequestOptions( - method="post", - url="/foo", - json_data={"foo": "bar"}, - ), - ) - assert request.url == "http://localhost:5000/custom/path/foo" - client.close() - - @pytest.mark.parametrize( - "client", - [ - Metronome( - base_url="http://localhost:5000/custom/path/", - bearer_token=bearer_token, - _strict_response_validation=True, - ), - Metronome( - base_url="http://localhost:5000/custom/path/", - bearer_token=bearer_token, - _strict_response_validation=True, - http_client=httpx.Client(), - ), - ], - ids=["standard", "custom http client"], - ) - def test_base_url_no_trailing_slash(self, client: Metronome) -> None: - request = client._build_request( - FinalRequestOptions( - method="post", - url="/foo", - json_data={"foo": "bar"}, - ), - ) - assert request.url == "http://localhost:5000/custom/path/foo" - client.close() - - @pytest.mark.parametrize( - "client", - [ - Metronome( - base_url="http://localhost:5000/custom/path/", - bearer_token=bearer_token, - _strict_response_validation=True, - ), - Metronome( - base_url="http://localhost:5000/custom/path/", - bearer_token=bearer_token, - _strict_response_validation=True, - http_client=httpx.Client(), - ), - ], - ids=["standard", "custom http client"], - ) - def test_absolute_request_url(self, client: Metronome) -> None: - request = client._build_request( - FinalRequestOptions( - method="post", - url="https://myapi.com/foo", - json_data={"foo": "bar"}, - ), - ) - assert request.url == "https://myapi.com/foo" - client.close() - - def test_copied_client_does_not_close_http(self) -> None: - test_client = Metronome(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True) - assert not test_client.is_closed() - - copied = test_client.copy() - assert copied is not test_client - - del copied - - assert not test_client.is_closed() - - def test_client_context_manager(self) -> None: - test_client = Metronome(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True) - with test_client as c2: - assert c2 is test_client - assert not c2.is_closed() - assert not test_client.is_closed() - assert test_client.is_closed() - - @pytest.mark.respx(base_url=base_url) - def test_client_response_validation_error(self, respx_mock: MockRouter, client: Metronome) -> None: - class Model(BaseModel): - foo: str - - respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": {"invalid": True}})) - - with pytest.raises(APIResponseValidationError) as exc: - client.get("/foo", cast_to=Model) - - assert isinstance(exc.value.__cause__, ValidationError) - - def test_client_max_retries_validation(self) -> None: - with pytest.raises(TypeError, match=r"max_retries cannot be None"): - Metronome( - base_url=base_url, - bearer_token=bearer_token, - _strict_response_validation=True, - max_retries=cast(Any, None), - ) - - @pytest.mark.respx(base_url=base_url) - def test_received_text_for_expected_json(self, respx_mock: MockRouter) -> None: - class Model(BaseModel): - name: str - - respx_mock.get("/foo").mock(return_value=httpx.Response(200, text="my-custom-format")) - - strict_client = Metronome(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True) - - with pytest.raises(APIResponseValidationError): - strict_client.get("/foo", cast_to=Model) - - non_strict_client = Metronome(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=False) - - response = non_strict_client.get("/foo", cast_to=Model) - assert isinstance(response, str) # type: ignore[unreachable] - - strict_client.close() - non_strict_client.close() - - @pytest.mark.parametrize( - "remaining_retries,retry_after,timeout", - [ - [3, "20", 20], - [3, "0", 0.5], - [3, "-10", 0.5], - [3, "60", 60], - [3, "61", 0.5], - [3, "Fri, 29 Sep 2023 16:26:57 GMT", 20], - [3, "Fri, 29 Sep 2023 16:26:37 GMT", 0.5], - [3, "Fri, 29 Sep 2023 16:26:27 GMT", 0.5], - [3, "Fri, 29 Sep 2023 16:27:37 GMT", 60], - [3, "Fri, 29 Sep 2023 16:27:38 GMT", 0.5], - [3, "99999999999999999999999999999999999", 0.5], - [3, "Zun, 29 Sep 2023 16:26:27 GMT", 0.5], - [3, "", 0.5], - [2, "", 0.5 * 2.0], - [1, "", 0.5 * 4.0], - [-1100, "", 8], # test large number potentially overflowing - ], - ) - @mock.patch("time.time", mock.MagicMock(return_value=1696004797)) - def test_parse_retry_after_header( - self, remaining_retries: int, retry_after: str, timeout: float, client: Metronome - ) -> None: - headers = httpx.Headers({"retry-after": retry_after}) - options = FinalRequestOptions(method="get", url="/foo", max_retries=3) - calculated = client._calculate_retry_timeout(remaining_retries, options, headers) - assert calculated == pytest.approx(timeout, 0.5 * 0.875) # pyright: ignore[reportUnknownMemberType] - - @mock.patch("metronome._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) - @pytest.mark.respx(base_url=base_url) - def test_retrying_timeout_errors_doesnt_leak(self, respx_mock: MockRouter, client: Metronome) -> None: - respx_mock.post("/v1/contracts/create").mock(side_effect=httpx.TimeoutException("Test timeout error")) - - with pytest.raises(APITimeoutError): - client.v1.contracts.with_streaming_response.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ).__enter__() - - assert _get_open_connections(client) == 0 - - @mock.patch("metronome._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) - @pytest.mark.respx(base_url=base_url) - def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter, client: Metronome) -> None: - respx_mock.post("/v1/contracts/create").mock(return_value=httpx.Response(500)) - - with pytest.raises(APIStatusError): - client.v1.contracts.with_streaming_response.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ).__enter__() - assert _get_open_connections(client) == 0 - - @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) - @mock.patch("metronome._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) - @pytest.mark.respx(base_url=base_url) - @pytest.mark.parametrize("failure_mode", ["status", "exception"]) - def test_retries_taken( - self, - client: Metronome, - failures_before_success: int, - failure_mode: Literal["status", "exception"], - respx_mock: MockRouter, - ) -> None: - client = client.with_options(max_retries=4) - - nb_retries = 0 - - def retry_handler(_request: httpx.Request) -> httpx.Response: - nonlocal nb_retries - if nb_retries < failures_before_success: - nb_retries += 1 - if failure_mode == "exception": - raise RuntimeError("oops") - return httpx.Response(500) - return httpx.Response(200) - - respx_mock.post("/v1/contracts/create").mock(side_effect=retry_handler) - - response = client.v1.contracts.with_raw_response.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", starting_at=parse_datetime("2020-01-01T00:00:00.000Z") - ) - - assert response.retries_taken == failures_before_success - assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success - - @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) - @mock.patch("metronome._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) - @pytest.mark.respx(base_url=base_url) - def test_omit_retry_count_header( - self, client: Metronome, failures_before_success: int, respx_mock: MockRouter - ) -> None: - client = client.with_options(max_retries=4) - - nb_retries = 0 - - def retry_handler(_request: httpx.Request) -> httpx.Response: - nonlocal nb_retries - if nb_retries < failures_before_success: - nb_retries += 1 - return httpx.Response(500) - return httpx.Response(200) - - respx_mock.post("/v1/contracts/create").mock(side_effect=retry_handler) - - response = client.v1.contracts.with_raw_response.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - extra_headers={"x-stainless-retry-count": Omit()}, - ) - - assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0 - - @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) - @mock.patch("metronome._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) - @pytest.mark.respx(base_url=base_url) - def test_overwrite_retry_count_header( - self, client: Metronome, failures_before_success: int, respx_mock: MockRouter - ) -> None: - client = client.with_options(max_retries=4) - - nb_retries = 0 - - def retry_handler(_request: httpx.Request) -> httpx.Response: - nonlocal nb_retries - if nb_retries < failures_before_success: - nb_retries += 1 - return httpx.Response(500) - return httpx.Response(200) - - respx_mock.post("/v1/contracts/create").mock(side_effect=retry_handler) - - response = client.v1.contracts.with_raw_response.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - extra_headers={"x-stainless-retry-count": "42"}, - ) - - assert response.http_request.headers.get("x-stainless-retry-count") == "42" - - def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: - # Test that the proxy environment variables are set correctly - monkeypatch.setenv("HTTPS_PROXY", "https://example.org") - # Delete in case our environment has any proxy env vars set - monkeypatch.delenv("HTTP_PROXY", raising=False) - monkeypatch.delenv("ALL_PROXY", raising=False) - monkeypatch.delenv("NO_PROXY", raising=False) - monkeypatch.delenv("http_proxy", raising=False) - monkeypatch.delenv("https_proxy", raising=False) - monkeypatch.delenv("all_proxy", raising=False) - monkeypatch.delenv("no_proxy", raising=False) - - client = DefaultHttpxClient() - - mounts = tuple(client._mounts.items()) - assert len(mounts) == 1 - assert mounts[0][0].pattern == "https://" - - @pytest.mark.filterwarnings("ignore:.*deprecated.*:DeprecationWarning") - def test_default_client_creation(self) -> None: - # Ensure that the client can be initialized without any exceptions - DefaultHttpxClient( - verify=True, - cert=None, - trust_env=True, - http1=True, - http2=False, - limits=httpx.Limits(max_connections=100, max_keepalive_connections=20), - ) - - @pytest.mark.respx(base_url=base_url) - def test_follow_redirects(self, respx_mock: MockRouter, client: Metronome) -> None: - # Test that the default follow_redirects=True allows following redirects - respx_mock.post("/redirect").mock( - return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) - ) - respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"})) - - response = client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) - assert response.status_code == 200 - assert response.json() == {"status": "ok"} - - @pytest.mark.respx(base_url=base_url) - def test_follow_redirects_disabled(self, respx_mock: MockRouter, client: Metronome) -> None: - # Test that follow_redirects=False prevents following redirects - respx_mock.post("/redirect").mock( - return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) - ) - - with pytest.raises(APIStatusError) as exc_info: - client.post("/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response) - - assert exc_info.value.response.status_code == 302 - assert exc_info.value.response.headers["Location"] == f"{base_url}/redirected" - - -class TestAsyncMetronome: - @pytest.mark.respx(base_url=base_url) - async def test_raw_response(self, respx_mock: MockRouter, async_client: AsyncMetronome) -> None: - respx_mock.post("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - - response = await async_client.post("/foo", cast_to=httpx.Response) - assert response.status_code == 200 - assert isinstance(response, httpx.Response) - assert response.json() == {"foo": "bar"} - - @pytest.mark.respx(base_url=base_url) - async def test_raw_response_for_binary(self, respx_mock: MockRouter, async_client: AsyncMetronome) -> None: - respx_mock.post("/foo").mock( - return_value=httpx.Response(200, headers={"Content-Type": "application/binary"}, content='{"foo": "bar"}') - ) - - response = await async_client.post("/foo", cast_to=httpx.Response) - assert response.status_code == 200 - assert isinstance(response, httpx.Response) - assert response.json() == {"foo": "bar"} - - def test_copy(self, async_client: AsyncMetronome) -> None: - copied = async_client.copy() - assert id(copied) != id(async_client) - - copied = async_client.copy(bearer_token="another My Bearer Token") - assert copied.bearer_token == "another My Bearer Token" - assert async_client.bearer_token == "My Bearer Token" - - def test_copy_default_options(self, async_client: AsyncMetronome) -> None: - # options that have a default are overridden correctly - copied = async_client.copy(max_retries=7) - assert copied.max_retries == 7 - assert async_client.max_retries == 2 - - copied2 = copied.copy(max_retries=6) - assert copied2.max_retries == 6 - assert copied.max_retries == 7 - - # timeout - assert isinstance(async_client.timeout, httpx.Timeout) - copied = async_client.copy(timeout=None) - assert copied.timeout is None - assert isinstance(async_client.timeout, httpx.Timeout) - - async def test_copy_default_headers(self) -> None: - client = AsyncMetronome( - base_url=base_url, - bearer_token=bearer_token, - _strict_response_validation=True, - default_headers={"X-Foo": "bar"}, - ) - assert client.default_headers["X-Foo"] == "bar" - - # does not override the already given value when not specified - copied = client.copy() - assert copied.default_headers["X-Foo"] == "bar" - - # merges already given headers - copied = client.copy(default_headers={"X-Bar": "stainless"}) - assert copied.default_headers["X-Foo"] == "bar" - assert copied.default_headers["X-Bar"] == "stainless" - - # uses new values for any already given headers - copied = client.copy(default_headers={"X-Foo": "stainless"}) - assert copied.default_headers["X-Foo"] == "stainless" - - # set_default_headers - - # completely overrides already set values - copied = client.copy(set_default_headers={}) - assert copied.default_headers.get("X-Foo") is None - - copied = client.copy(set_default_headers={"X-Bar": "Robert"}) - assert copied.default_headers["X-Bar"] == "Robert" - - with pytest.raises( - ValueError, - match="`default_headers` and `set_default_headers` arguments are mutually exclusive", - ): - client.copy(set_default_headers={}, default_headers={"X-Foo": "Bar"}) - await client.close() - - async def test_copy_default_query(self) -> None: - client = AsyncMetronome( - base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True, default_query={"foo": "bar"} - ) - assert _get_params(client)["foo"] == "bar" - - # does not override the already given value when not specified - copied = client.copy() - assert _get_params(copied)["foo"] == "bar" - - # merges already given params - copied = client.copy(default_query={"bar": "stainless"}) - params = _get_params(copied) - assert params["foo"] == "bar" - assert params["bar"] == "stainless" - - # uses new values for any already given headers - copied = client.copy(default_query={"foo": "stainless"}) - assert _get_params(copied)["foo"] == "stainless" - - # set_default_query - - # completely overrides already set values - copied = client.copy(set_default_query={}) - assert _get_params(copied) == {} - - copied = client.copy(set_default_query={"bar": "Robert"}) - assert _get_params(copied)["bar"] == "Robert" - - with pytest.raises( - ValueError, - # TODO: update - match="`default_query` and `set_default_query` arguments are mutually exclusive", - ): - client.copy(set_default_query={}, default_query={"foo": "Bar"}) - - await client.close() - - def test_copy_signature(self, async_client: AsyncMetronome) -> None: - # ensure the same parameters that can be passed to the client are defined in the `.copy()` method - init_signature = inspect.signature( - # mypy doesn't like that we access the `__init__` property. - async_client.__init__, # type: ignore[misc] - ) - copy_signature = inspect.signature(async_client.copy) - exclude_params = {"transport", "proxies", "_strict_response_validation"} - - for name in init_signature.parameters.keys(): - if name in exclude_params: - continue - - copy_param = copy_signature.parameters.get(name) - assert copy_param is not None, f"copy() signature is missing the {name} param" - - @pytest.mark.skipif(sys.version_info >= (3, 10), reason="fails because of a memory leak that started from 3.12") - def test_copy_build_request(self, async_client: AsyncMetronome) -> None: - options = FinalRequestOptions(method="get", url="/foo") - - def build_request(options: FinalRequestOptions) -> None: - client_copy = async_client.copy() - client_copy._build_request(options) - - # ensure that the machinery is warmed up before tracing starts. - build_request(options) - gc.collect() - - tracemalloc.start(1000) - - snapshot_before = tracemalloc.take_snapshot() - - ITERATIONS = 10 - for _ in range(ITERATIONS): - build_request(options) - - gc.collect() - snapshot_after = tracemalloc.take_snapshot() - - tracemalloc.stop() - - def add_leak(leaks: list[tracemalloc.StatisticDiff], diff: tracemalloc.StatisticDiff) -> None: - if diff.count == 0: - # Avoid false positives by considering only leaks (i.e. allocations that persist). - return - - if diff.count % ITERATIONS != 0: - # Avoid false positives by considering only leaks that appear per iteration. - return - - for frame in diff.traceback: - if any( - frame.filename.endswith(fragment) - for fragment in [ - # to_raw_response_wrapper leaks through the @functools.wraps() decorator. - # - # removing the decorator fixes the leak for reasons we don't understand. - "metronome/_legacy_response.py", - "metronome/_response.py", - # pydantic.BaseModel.model_dump || pydantic.BaseModel.dict leak memory for some reason. - "metronome/_compat.py", - # Standard library leaks we don't care about. - "/logging/__init__.py", - ] - ): - return - - leaks.append(diff) - - leaks: list[tracemalloc.StatisticDiff] = [] - for diff in snapshot_after.compare_to(snapshot_before, "traceback"): - add_leak(leaks, diff) - if leaks: - for leak in leaks: - print("MEMORY LEAK:", leak) - for frame in leak.traceback: - print(frame) - raise AssertionError() - - async def test_request_timeout(self, async_client: AsyncMetronome) -> None: - request = async_client._build_request(FinalRequestOptions(method="get", url="/foo")) - timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore - assert timeout == DEFAULT_TIMEOUT - - request = async_client._build_request( - FinalRequestOptions(method="get", url="/foo", timeout=httpx.Timeout(100.0)) - ) - timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore - assert timeout == httpx.Timeout(100.0) - - async def test_client_timeout_option(self) -> None: - client = AsyncMetronome( - base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True, timeout=httpx.Timeout(0) - ) - - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) - timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore - assert timeout == httpx.Timeout(0) - - await client.close() - - async def test_http_client_timeout_option(self) -> None: - # custom timeout given to the httpx client should be used - async with httpx.AsyncClient(timeout=None) as http_client: - client = AsyncMetronome( - base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True, http_client=http_client - ) - - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) - timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore - assert timeout == httpx.Timeout(None) - - await client.close() - - # no timeout given to the httpx client should not use the httpx default - async with httpx.AsyncClient() as http_client: - client = AsyncMetronome( - base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True, http_client=http_client - ) - - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) - timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore - assert timeout == DEFAULT_TIMEOUT - - await client.close() - - # explicitly passing the default timeout currently results in it being ignored - async with httpx.AsyncClient(timeout=HTTPX_DEFAULT_TIMEOUT) as http_client: - client = AsyncMetronome( - base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True, http_client=http_client - ) - - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) - timeout = httpx.Timeout(**request.extensions["timeout"]) # type: ignore - assert timeout == DEFAULT_TIMEOUT # our default - - await client.close() - - def test_invalid_http_client(self) -> None: - with pytest.raises(TypeError, match="Invalid `http_client` arg"): - with httpx.Client() as http_client: - AsyncMetronome( - base_url=base_url, - bearer_token=bearer_token, - _strict_response_validation=True, - http_client=cast(Any, http_client), - ) - - async def test_default_headers_option(self) -> None: - test_client = AsyncMetronome( - base_url=base_url, - bearer_token=bearer_token, - _strict_response_validation=True, - default_headers={"X-Foo": "bar"}, - ) - request = test_client._build_request(FinalRequestOptions(method="get", url="/foo")) - assert request.headers.get("x-foo") == "bar" - assert request.headers.get("x-stainless-lang") == "python" - - test_client2 = AsyncMetronome( - base_url=base_url, - bearer_token=bearer_token, - _strict_response_validation=True, - default_headers={ - "X-Foo": "stainless", - "X-Stainless-Lang": "my-overriding-header", - }, - ) - request = test_client2._build_request(FinalRequestOptions(method="get", url="/foo")) - assert request.headers.get("x-foo") == "stainless" - assert request.headers.get("x-stainless-lang") == "my-overriding-header" - - await test_client.close() - await test_client2.close() - - def test_validate_headers(self) -> None: - client = AsyncMetronome(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True) - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) - assert request.headers.get("Authorization") == f"Bearer {bearer_token}" - - with pytest.raises(MetronomeError): - with update_env(**{"METRONOME_BEARER_TOKEN": Omit()}): - client2 = AsyncMetronome(base_url=base_url, bearer_token=None, _strict_response_validation=True) - _ = client2 - - async def test_default_query_option(self) -> None: - client = AsyncMetronome( - base_url=base_url, - bearer_token=bearer_token, - _strict_response_validation=True, - default_query={"query_param": "bar"}, - ) - request = client._build_request(FinalRequestOptions(method="get", url="/foo")) - url = httpx.URL(request.url) - assert dict(url.params) == {"query_param": "bar"} - - request = client._build_request( - FinalRequestOptions( - method="get", - url="/foo", - params={"foo": "baz", "query_param": "overridden"}, - ) - ) - url = httpx.URL(request.url) - assert dict(url.params) == {"foo": "baz", "query_param": "overridden"} - - await client.close() - - def test_request_extra_json(self, client: Metronome) -> None: - request = client._build_request( - FinalRequestOptions( - method="post", - url="/foo", - json_data={"foo": "bar"}, - extra_json={"baz": False}, - ), - ) - data = json.loads(request.content.decode("utf-8")) - assert data == {"foo": "bar", "baz": False} - - request = client._build_request( - FinalRequestOptions( - method="post", - url="/foo", - extra_json={"baz": False}, - ), - ) - data = json.loads(request.content.decode("utf-8")) - assert data == {"baz": False} - - # `extra_json` takes priority over `json_data` when keys clash - request = client._build_request( - FinalRequestOptions( - method="post", - url="/foo", - json_data={"foo": "bar", "baz": True}, - extra_json={"baz": None}, - ), - ) - data = json.loads(request.content.decode("utf-8")) - assert data == {"foo": "bar", "baz": None} - - def test_request_extra_headers(self, client: Metronome) -> None: - request = client._build_request( - FinalRequestOptions( - method="post", - url="/foo", - **make_request_options(extra_headers={"X-Foo": "Foo"}), - ), - ) - assert request.headers.get("X-Foo") == "Foo" - - # `extra_headers` takes priority over `default_headers` when keys clash - request = client.with_options(default_headers={"X-Bar": "true"})._build_request( - FinalRequestOptions( - method="post", - url="/foo", - **make_request_options( - extra_headers={"X-Bar": "false"}, - ), - ), - ) - assert request.headers.get("X-Bar") == "false" - - def test_request_extra_query(self, client: Metronome) -> None: - request = client._build_request( - FinalRequestOptions( - method="post", - url="/foo", - **make_request_options( - extra_query={"my_query_param": "Foo"}, - ), - ), - ) - params = dict(request.url.params) - assert params == {"my_query_param": "Foo"} - - # if both `query` and `extra_query` are given, they are merged - request = client._build_request( - FinalRequestOptions( - method="post", - url="/foo", - **make_request_options( - query={"bar": "1"}, - extra_query={"foo": "2"}, - ), - ), - ) - params = dict(request.url.params) - assert params == {"bar": "1", "foo": "2"} - - # `extra_query` takes priority over `query` when keys clash - request = client._build_request( - FinalRequestOptions( - method="post", - url="/foo", - **make_request_options( - query={"foo": "1"}, - extra_query={"foo": "2"}, - ), - ), - ) - params = dict(request.url.params) - assert params == {"foo": "2"} - - def test_multipart_repeating_array(self, async_client: AsyncMetronome) -> None: - request = async_client._build_request( - FinalRequestOptions.construct( - method="post", - url="/foo", - headers={"Content-Type": "multipart/form-data; boundary=6b7ba517decee4a450543ea6ae821c82"}, - json_data={"array": ["foo", "bar"]}, - files=[("foo.txt", b"hello world")], - ) - ) - - assert request.read().split(b"\r\n") == [ - b"--6b7ba517decee4a450543ea6ae821c82", - b'Content-Disposition: form-data; name="array[]"', - b"", - b"foo", - b"--6b7ba517decee4a450543ea6ae821c82", - b'Content-Disposition: form-data; name="array[]"', - b"", - b"bar", - b"--6b7ba517decee4a450543ea6ae821c82", - b'Content-Disposition: form-data; name="foo.txt"; filename="upload"', - b"Content-Type: application/octet-stream", - b"", - b"hello world", - b"--6b7ba517decee4a450543ea6ae821c82--", - b"", - ] - - @pytest.mark.respx(base_url=base_url) - async def test_binary_content_upload(self, respx_mock: MockRouter, async_client: AsyncMetronome) -> None: - respx_mock.post("/upload").mock(side_effect=mirror_request_content) - - file_content = b"Hello, this is a test file." - - response = await async_client.post( - "/upload", - content=file_content, - cast_to=httpx.Response, - options={"headers": {"Content-Type": "application/octet-stream"}}, - ) - - assert response.status_code == 200 - assert response.request.headers["Content-Type"] == "application/octet-stream" - assert response.content == file_content - - async def test_binary_content_upload_with_asynciterator(self) -> None: - file_content = b"Hello, this is a test file." - counter = Counter() - iterator = _make_async_iterator([file_content], counter=counter) - - async def mock_handler(request: httpx.Request) -> httpx.Response: - assert counter.value == 0, "the request body should not have been read" - return httpx.Response(200, content=await request.aread()) - - async with AsyncMetronome( - base_url=base_url, - bearer_token=bearer_token, - _strict_response_validation=True, - http_client=httpx.AsyncClient(transport=MockTransport(handler=mock_handler)), - ) as client: - response = await client.post( - "/upload", - content=iterator, - cast_to=httpx.Response, - options={"headers": {"Content-Type": "application/octet-stream"}}, - ) - - assert response.status_code == 200 - assert response.request.headers["Content-Type"] == "application/octet-stream" - assert response.content == file_content - assert counter.value == 1 - - @pytest.mark.respx(base_url=base_url) - async def test_binary_content_upload_with_body_is_deprecated( - self, respx_mock: MockRouter, async_client: AsyncMetronome - ) -> None: - respx_mock.post("/upload").mock(side_effect=mirror_request_content) - - file_content = b"Hello, this is a test file." - - with pytest.deprecated_call( - match="Passing raw bytes as `body` is deprecated and will be removed in a future version. Please pass raw bytes via the `content` parameter instead." - ): - response = await async_client.post( - "/upload", - body=file_content, - cast_to=httpx.Response, - options={"headers": {"Content-Type": "application/octet-stream"}}, - ) - - assert response.status_code == 200 - assert response.request.headers["Content-Type"] == "application/octet-stream" - assert response.content == file_content - - @pytest.mark.respx(base_url=base_url) - async def test_basic_union_response(self, respx_mock: MockRouter, async_client: AsyncMetronome) -> None: - class Model1(BaseModel): - name: str - - class Model2(BaseModel): - foo: str - - respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - - response = await async_client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) - assert isinstance(response, Model2) - assert response.foo == "bar" - - @pytest.mark.respx(base_url=base_url) - async def test_union_response_different_types(self, respx_mock: MockRouter, async_client: AsyncMetronome) -> None: - """Union of objects with the same field name using a different type""" - - class Model1(BaseModel): - foo: int - - class Model2(BaseModel): - foo: str - - respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": "bar"})) - - response = await async_client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) - assert isinstance(response, Model2) - assert response.foo == "bar" - - respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": 1})) - - response = await async_client.get("/foo", cast_to=cast(Any, Union[Model1, Model2])) - assert isinstance(response, Model1) - assert response.foo == 1 - - @pytest.mark.respx(base_url=base_url) - async def test_non_application_json_content_type_for_json_data( - self, respx_mock: MockRouter, async_client: AsyncMetronome - ) -> None: - """ - Response that sets Content-Type to something other than application/json but returns json data - """ - - class Model(BaseModel): - foo: int - - respx_mock.get("/foo").mock( - return_value=httpx.Response( - 200, - content=json.dumps({"foo": 2}), - headers={"Content-Type": "application/text"}, - ) - ) - - response = await async_client.get("/foo", cast_to=Model) - assert isinstance(response, Model) - assert response.foo == 2 - - async def test_base_url_setter(self) -> None: - client = AsyncMetronome( - base_url="https://example.com/from_init", bearer_token=bearer_token, _strict_response_validation=True - ) - assert client.base_url == "https://example.com/from_init/" - - client.base_url = "https://example.com/from_setter" # type: ignore[assignment] - - assert client.base_url == "https://example.com/from_setter/" - - await client.close() - - async def test_base_url_env(self) -> None: - with update_env(METRONOME_BASE_URL="http://localhost:5000/from/env"): - client = AsyncMetronome(bearer_token=bearer_token, _strict_response_validation=True) - assert client.base_url == "http://localhost:5000/from/env/" - - @pytest.mark.parametrize( - "client", - [ - AsyncMetronome( - base_url="http://localhost:5000/custom/path/", - bearer_token=bearer_token, - _strict_response_validation=True, - ), - AsyncMetronome( - base_url="http://localhost:5000/custom/path/", - bearer_token=bearer_token, - _strict_response_validation=True, - http_client=httpx.AsyncClient(), - ), - ], - ids=["standard", "custom http client"], - ) - async def test_base_url_trailing_slash(self, client: AsyncMetronome) -> None: - request = client._build_request( - FinalRequestOptions( - method="post", - url="/foo", - json_data={"foo": "bar"}, - ), - ) - assert request.url == "http://localhost:5000/custom/path/foo" - await client.close() - - @pytest.mark.parametrize( - "client", - [ - AsyncMetronome( - base_url="http://localhost:5000/custom/path/", - bearer_token=bearer_token, - _strict_response_validation=True, - ), - AsyncMetronome( - base_url="http://localhost:5000/custom/path/", - bearer_token=bearer_token, - _strict_response_validation=True, - http_client=httpx.AsyncClient(), - ), - ], - ids=["standard", "custom http client"], - ) - async def test_base_url_no_trailing_slash(self, client: AsyncMetronome) -> None: - request = client._build_request( - FinalRequestOptions( - method="post", - url="/foo", - json_data={"foo": "bar"}, - ), - ) - assert request.url == "http://localhost:5000/custom/path/foo" - await client.close() - - @pytest.mark.parametrize( - "client", - [ - AsyncMetronome( - base_url="http://localhost:5000/custom/path/", - bearer_token=bearer_token, - _strict_response_validation=True, - ), - AsyncMetronome( - base_url="http://localhost:5000/custom/path/", - bearer_token=bearer_token, - _strict_response_validation=True, - http_client=httpx.AsyncClient(), - ), - ], - ids=["standard", "custom http client"], - ) - async def test_absolute_request_url(self, client: AsyncMetronome) -> None: - request = client._build_request( - FinalRequestOptions( - method="post", - url="https://myapi.com/foo", - json_data={"foo": "bar"}, - ), - ) - assert request.url == "https://myapi.com/foo" - await client.close() - - async def test_copied_client_does_not_close_http(self) -> None: - test_client = AsyncMetronome(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True) - assert not test_client.is_closed() - - copied = test_client.copy() - assert copied is not test_client - - del copied - - await asyncio.sleep(0.2) - assert not test_client.is_closed() - - async def test_client_context_manager(self) -> None: - test_client = AsyncMetronome(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True) - async with test_client as c2: - assert c2 is test_client - assert not c2.is_closed() - assert not test_client.is_closed() - assert test_client.is_closed() - - @pytest.mark.respx(base_url=base_url) - async def test_client_response_validation_error(self, respx_mock: MockRouter, async_client: AsyncMetronome) -> None: - class Model(BaseModel): - foo: str - - respx_mock.get("/foo").mock(return_value=httpx.Response(200, json={"foo": {"invalid": True}})) - - with pytest.raises(APIResponseValidationError) as exc: - await async_client.get("/foo", cast_to=Model) - - assert isinstance(exc.value.__cause__, ValidationError) - - async def test_client_max_retries_validation(self) -> None: - with pytest.raises(TypeError, match=r"max_retries cannot be None"): - AsyncMetronome( - base_url=base_url, - bearer_token=bearer_token, - _strict_response_validation=True, - max_retries=cast(Any, None), - ) - - @pytest.mark.respx(base_url=base_url) - async def test_received_text_for_expected_json(self, respx_mock: MockRouter) -> None: - class Model(BaseModel): - name: str - - respx_mock.get("/foo").mock(return_value=httpx.Response(200, text="my-custom-format")) - - strict_client = AsyncMetronome(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True) - - with pytest.raises(APIResponseValidationError): - await strict_client.get("/foo", cast_to=Model) - - non_strict_client = AsyncMetronome( - base_url=base_url, bearer_token=bearer_token, _strict_response_validation=False - ) - - response = await non_strict_client.get("/foo", cast_to=Model) - assert isinstance(response, str) # type: ignore[unreachable] - - await strict_client.close() - await non_strict_client.close() - - @pytest.mark.parametrize( - "remaining_retries,retry_after,timeout", - [ - [3, "20", 20], - [3, "0", 0.5], - [3, "-10", 0.5], - [3, "60", 60], - [3, "61", 0.5], - [3, "Fri, 29 Sep 2023 16:26:57 GMT", 20], - [3, "Fri, 29 Sep 2023 16:26:37 GMT", 0.5], - [3, "Fri, 29 Sep 2023 16:26:27 GMT", 0.5], - [3, "Fri, 29 Sep 2023 16:27:37 GMT", 60], - [3, "Fri, 29 Sep 2023 16:27:38 GMT", 0.5], - [3, "99999999999999999999999999999999999", 0.5], - [3, "Zun, 29 Sep 2023 16:26:27 GMT", 0.5], - [3, "", 0.5], - [2, "", 0.5 * 2.0], - [1, "", 0.5 * 4.0], - [-1100, "", 8], # test large number potentially overflowing - ], - ) - @mock.patch("time.time", mock.MagicMock(return_value=1696004797)) - async def test_parse_retry_after_header( - self, remaining_retries: int, retry_after: str, timeout: float, async_client: AsyncMetronome - ) -> None: - headers = httpx.Headers({"retry-after": retry_after}) - options = FinalRequestOptions(method="get", url="/foo", max_retries=3) - calculated = async_client._calculate_retry_timeout(remaining_retries, options, headers) - assert calculated == pytest.approx(timeout, 0.5 * 0.875) # pyright: ignore[reportUnknownMemberType] - - @mock.patch("metronome._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) - @pytest.mark.respx(base_url=base_url) - async def test_retrying_timeout_errors_doesnt_leak( - self, respx_mock: MockRouter, async_client: AsyncMetronome - ) -> None: - respx_mock.post("/v1/contracts/create").mock(side_effect=httpx.TimeoutException("Test timeout error")) - - with pytest.raises(APITimeoutError): - await async_client.v1.contracts.with_streaming_response.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ).__aenter__() - - assert _get_open_connections(async_client) == 0 - - @mock.patch("metronome._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) - @pytest.mark.respx(base_url=base_url) - async def test_retrying_status_errors_doesnt_leak( - self, respx_mock: MockRouter, async_client: AsyncMetronome - ) -> None: - respx_mock.post("/v1/contracts/create").mock(return_value=httpx.Response(500)) - - with pytest.raises(APIStatusError): - await async_client.v1.contracts.with_streaming_response.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - ).__aenter__() - assert _get_open_connections(async_client) == 0 - - @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) - @mock.patch("metronome._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) - @pytest.mark.respx(base_url=base_url) - @pytest.mark.parametrize("failure_mode", ["status", "exception"]) - async def test_retries_taken( - self, - async_client: AsyncMetronome, - failures_before_success: int, - failure_mode: Literal["status", "exception"], - respx_mock: MockRouter, - ) -> None: - client = async_client.with_options(max_retries=4) - - nb_retries = 0 - - def retry_handler(_request: httpx.Request) -> httpx.Response: - nonlocal nb_retries - if nb_retries < failures_before_success: - nb_retries += 1 - if failure_mode == "exception": - raise RuntimeError("oops") - return httpx.Response(500) - return httpx.Response(200) - - respx_mock.post("/v1/contracts/create").mock(side_effect=retry_handler) - - response = await client.v1.contracts.with_raw_response.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", starting_at=parse_datetime("2020-01-01T00:00:00.000Z") - ) - - assert response.retries_taken == failures_before_success - assert int(response.http_request.headers.get("x-stainless-retry-count")) == failures_before_success - - @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) - @mock.patch("metronome._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) - @pytest.mark.respx(base_url=base_url) - async def test_omit_retry_count_header( - self, async_client: AsyncMetronome, failures_before_success: int, respx_mock: MockRouter - ) -> None: - client = async_client.with_options(max_retries=4) - - nb_retries = 0 - - def retry_handler(_request: httpx.Request) -> httpx.Response: - nonlocal nb_retries - if nb_retries < failures_before_success: - nb_retries += 1 - return httpx.Response(500) - return httpx.Response(200) - - respx_mock.post("/v1/contracts/create").mock(side_effect=retry_handler) - - response = await client.v1.contracts.with_raw_response.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - extra_headers={"x-stainless-retry-count": Omit()}, - ) - - assert len(response.http_request.headers.get_list("x-stainless-retry-count")) == 0 - - @pytest.mark.parametrize("failures_before_success", [0, 2, 4]) - @mock.patch("metronome._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) - @pytest.mark.respx(base_url=base_url) - async def test_overwrite_retry_count_header( - self, async_client: AsyncMetronome, failures_before_success: int, respx_mock: MockRouter - ) -> None: - client = async_client.with_options(max_retries=4) - - nb_retries = 0 - - def retry_handler(_request: httpx.Request) -> httpx.Response: - nonlocal nb_retries - if nb_retries < failures_before_success: - nb_retries += 1 - return httpx.Response(500) - return httpx.Response(200) - - respx_mock.post("/v1/contracts/create").mock(side_effect=retry_handler) - - response = await client.v1.contracts.with_raw_response.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - extra_headers={"x-stainless-retry-count": "42"}, - ) - - assert response.http_request.headers.get("x-stainless-retry-count") == "42" - - async def test_get_platform(self) -> None: - platform = await asyncify(get_platform)() - assert isinstance(platform, (str, OtherPlatform)) - - async def test_proxy_environment_variables(self, monkeypatch: pytest.MonkeyPatch) -> None: - # Test that the proxy environment variables are set correctly - monkeypatch.setenv("HTTPS_PROXY", "https://example.org") - # Delete in case our environment has any proxy env vars set - monkeypatch.delenv("HTTP_PROXY", raising=False) - monkeypatch.delenv("ALL_PROXY", raising=False) - monkeypatch.delenv("NO_PROXY", raising=False) - monkeypatch.delenv("http_proxy", raising=False) - monkeypatch.delenv("https_proxy", raising=False) - monkeypatch.delenv("all_proxy", raising=False) - monkeypatch.delenv("no_proxy", raising=False) - - client = DefaultAsyncHttpxClient() - - mounts = tuple(client._mounts.items()) - assert len(mounts) == 1 - assert mounts[0][0].pattern == "https://" - - @pytest.mark.filterwarnings("ignore:.*deprecated.*:DeprecationWarning") - async def test_default_client_creation(self) -> None: - # Ensure that the client can be initialized without any exceptions - DefaultAsyncHttpxClient( - verify=True, - cert=None, - trust_env=True, - http1=True, - http2=False, - limits=httpx.Limits(max_connections=100, max_keepalive_connections=20), - ) - - @pytest.mark.respx(base_url=base_url) - async def test_follow_redirects(self, respx_mock: MockRouter, async_client: AsyncMetronome) -> None: - # Test that the default follow_redirects=True allows following redirects - respx_mock.post("/redirect").mock( - return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) - ) - respx_mock.get("/redirected").mock(return_value=httpx.Response(200, json={"status": "ok"})) - - response = await async_client.post("/redirect", body={"key": "value"}, cast_to=httpx.Response) - assert response.status_code == 200 - assert response.json() == {"status": "ok"} - - @pytest.mark.respx(base_url=base_url) - async def test_follow_redirects_disabled(self, respx_mock: MockRouter, async_client: AsyncMetronome) -> None: - # Test that follow_redirects=False prevents following redirects - respx_mock.post("/redirect").mock( - return_value=httpx.Response(302, headers={"Location": f"{base_url}/redirected"}) - ) - - with pytest.raises(APIStatusError) as exc_info: - await async_client.post( - "/redirect", body={"key": "value"}, options={"follow_redirects": False}, cast_to=httpx.Response - ) - - assert exc_info.value.response.status_code == 302 - assert exc_info.value.response.headers["Location"] == f"{base_url}/redirected" diff --git a/tests/test_deepcopy.py b/tests/test_deepcopy.py deleted file mode 100644 index 521603a8c..000000000 --- a/tests/test_deepcopy.py +++ /dev/null @@ -1,58 +0,0 @@ -from metronome._utils import deepcopy_minimal - - -def assert_different_identities(obj1: object, obj2: object) -> None: - assert obj1 == obj2 - assert id(obj1) != id(obj2) - - -def test_simple_dict() -> None: - obj1 = {"foo": "bar"} - obj2 = deepcopy_minimal(obj1) - assert_different_identities(obj1, obj2) - - -def test_nested_dict() -> None: - obj1 = {"foo": {"bar": True}} - obj2 = deepcopy_minimal(obj1) - assert_different_identities(obj1, obj2) - assert_different_identities(obj1["foo"], obj2["foo"]) - - -def test_complex_nested_dict() -> None: - obj1 = {"foo": {"bar": [{"hello": "world"}]}} - obj2 = deepcopy_minimal(obj1) - assert_different_identities(obj1, obj2) - assert_different_identities(obj1["foo"], obj2["foo"]) - assert_different_identities(obj1["foo"]["bar"], obj2["foo"]["bar"]) - assert_different_identities(obj1["foo"]["bar"][0], obj2["foo"]["bar"][0]) - - -def test_simple_list() -> None: - obj1 = ["a", "b", "c"] - obj2 = deepcopy_minimal(obj1) - assert_different_identities(obj1, obj2) - - -def test_nested_list() -> None: - obj1 = ["a", [1, 2, 3]] - obj2 = deepcopy_minimal(obj1) - assert_different_identities(obj1, obj2) - assert_different_identities(obj1[1], obj2[1]) - - -class MyObject: ... - - -def test_ignores_other_types() -> None: - # custom classes - my_obj = MyObject() - obj1 = {"foo": my_obj} - obj2 = deepcopy_minimal(obj1) - assert_different_identities(obj1, obj2) - assert obj1["foo"] is my_obj - - # tuples - obj3 = ("a", "b") - obj4 = deepcopy_minimal(obj3) - assert obj3 is obj4 diff --git a/tests/test_extract_files.py b/tests/test_extract_files.py deleted file mode 100644 index f614b6aff..000000000 --- a/tests/test_extract_files.py +++ /dev/null @@ -1,64 +0,0 @@ -from __future__ import annotations - -from typing import Sequence - -import pytest - -from metronome._types import FileTypes -from metronome._utils import extract_files - - -def test_removes_files_from_input() -> None: - query = {"foo": "bar"} - assert extract_files(query, paths=[]) == [] - assert query == {"foo": "bar"} - - query2 = {"foo": b"Bar", "hello": "world"} - assert extract_files(query2, paths=[["foo"]]) == [("foo", b"Bar")] - assert query2 == {"hello": "world"} - - query3 = {"foo": {"foo": {"bar": b"Bar"}}, "hello": "world"} - assert extract_files(query3, paths=[["foo", "foo", "bar"]]) == [("foo[foo][bar]", b"Bar")] - assert query3 == {"foo": {"foo": {}}, "hello": "world"} - - query4 = {"foo": {"bar": b"Bar", "baz": "foo"}, "hello": "world"} - assert extract_files(query4, paths=[["foo", "bar"]]) == [("foo[bar]", b"Bar")] - assert query4 == {"hello": "world", "foo": {"baz": "foo"}} - - -def test_multiple_files() -> None: - query = {"documents": [{"file": b"My first file"}, {"file": b"My second file"}]} - assert extract_files(query, paths=[["documents", "", "file"]]) == [ - ("documents[][file]", b"My first file"), - ("documents[][file]", b"My second file"), - ] - assert query == {"documents": [{}, {}]} - - -@pytest.mark.parametrize( - "query,paths,expected", - [ - [ - {"foo": {"bar": "baz"}}, - [["foo", "", "bar"]], - [], - ], - [ - {"foo": ["bar", "baz"]}, - [["foo", "bar"]], - [], - ], - [ - {"foo": {"bar": "baz"}}, - [["foo", "foo"]], - [], - ], - ], - ids=["dict expecting array", "array expecting dict", "unknown keys"], -) -def test_ignores_incorrect_paths( - query: dict[str, object], - paths: Sequence[Sequence[str]], - expected: list[tuple[str, FileTypes]], -) -> None: - assert extract_files(query, paths=paths) == expected diff --git a/tests/test_files.py b/tests/test_files.py deleted file mode 100644 index ade80277f..000000000 --- a/tests/test_files.py +++ /dev/null @@ -1,51 +0,0 @@ -from pathlib import Path - -import anyio -import pytest -from dirty_equals import IsDict, IsList, IsBytes, IsTuple - -from metronome._files import to_httpx_files, async_to_httpx_files - -readme_path = Path(__file__).parent.parent.joinpath("README.md") - - -def test_pathlib_includes_file_name() -> None: - result = to_httpx_files({"file": readme_path}) - print(result) - assert result == IsDict({"file": IsTuple("README.md", IsBytes())}) - - -def test_tuple_input() -> None: - result = to_httpx_files([("file", readme_path)]) - print(result) - assert result == IsList(IsTuple("file", IsTuple("README.md", IsBytes()))) - - -@pytest.mark.asyncio -async def test_async_pathlib_includes_file_name() -> None: - result = await async_to_httpx_files({"file": readme_path}) - print(result) - assert result == IsDict({"file": IsTuple("README.md", IsBytes())}) - - -@pytest.mark.asyncio -async def test_async_supports_anyio_path() -> None: - result = await async_to_httpx_files({"file": anyio.Path(readme_path)}) - print(result) - assert result == IsDict({"file": IsTuple("README.md", IsBytes())}) - - -@pytest.mark.asyncio -async def test_async_tuple_input() -> None: - result = await async_to_httpx_files([("file", readme_path)]) - print(result) - assert result == IsList(IsTuple("file", IsTuple("README.md", IsBytes()))) - - -def test_string_not_allowed() -> None: - with pytest.raises(TypeError, match="Expected file types input to be a FileContent type or to be a tuple"): - to_httpx_files( - { - "file": "foo", # type: ignore - } - ) diff --git a/tests/test_models.py b/tests/test_models.py deleted file mode 100644 index 91482fecd..000000000 --- a/tests/test_models.py +++ /dev/null @@ -1,963 +0,0 @@ -import json -from typing import TYPE_CHECKING, Any, Dict, List, Union, Optional, cast -from datetime import datetime, timezone -from typing_extensions import Literal, Annotated, TypeAliasType - -import pytest -import pydantic -from pydantic import Field - -from metronome._utils import PropertyInfo -from metronome._compat import PYDANTIC_V1, parse_obj, model_dump, model_json -from metronome._models import DISCRIMINATOR_CACHE, BaseModel, construct_type - - -class BasicModel(BaseModel): - foo: str - - -@pytest.mark.parametrize("value", ["hello", 1], ids=["correct type", "mismatched"]) -def test_basic(value: object) -> None: - m = BasicModel.construct(foo=value) - assert m.foo == value - - -def test_directly_nested_model() -> None: - class NestedModel(BaseModel): - nested: BasicModel - - m = NestedModel.construct(nested={"foo": "Foo!"}) - assert m.nested.foo == "Foo!" - - # mismatched types - m = NestedModel.construct(nested="hello!") - assert cast(Any, m.nested) == "hello!" - - -def test_optional_nested_model() -> None: - class NestedModel(BaseModel): - nested: Optional[BasicModel] - - m1 = NestedModel.construct(nested=None) - assert m1.nested is None - - m2 = NestedModel.construct(nested={"foo": "bar"}) - assert m2.nested is not None - assert m2.nested.foo == "bar" - - # mismatched types - m3 = NestedModel.construct(nested={"foo"}) - assert isinstance(cast(Any, m3.nested), set) - assert cast(Any, m3.nested) == {"foo"} - - -def test_list_nested_model() -> None: - class NestedModel(BaseModel): - nested: List[BasicModel] - - m = NestedModel.construct(nested=[{"foo": "bar"}, {"foo": "2"}]) - assert m.nested is not None - assert isinstance(m.nested, list) - assert len(m.nested) == 2 - assert m.nested[0].foo == "bar" - assert m.nested[1].foo == "2" - - # mismatched types - m = NestedModel.construct(nested=True) - assert cast(Any, m.nested) is True - - m = NestedModel.construct(nested=[False]) - assert cast(Any, m.nested) == [False] - - -def test_optional_list_nested_model() -> None: - class NestedModel(BaseModel): - nested: Optional[List[BasicModel]] - - m1 = NestedModel.construct(nested=[{"foo": "bar"}, {"foo": "2"}]) - assert m1.nested is not None - assert isinstance(m1.nested, list) - assert len(m1.nested) == 2 - assert m1.nested[0].foo == "bar" - assert m1.nested[1].foo == "2" - - m2 = NestedModel.construct(nested=None) - assert m2.nested is None - - # mismatched types - m3 = NestedModel.construct(nested={1}) - assert cast(Any, m3.nested) == {1} - - m4 = NestedModel.construct(nested=[False]) - assert cast(Any, m4.nested) == [False] - - -def test_list_optional_items_nested_model() -> None: - class NestedModel(BaseModel): - nested: List[Optional[BasicModel]] - - m = NestedModel.construct(nested=[None, {"foo": "bar"}]) - assert m.nested is not None - assert isinstance(m.nested, list) - assert len(m.nested) == 2 - assert m.nested[0] is None - assert m.nested[1] is not None - assert m.nested[1].foo == "bar" - - # mismatched types - m3 = NestedModel.construct(nested="foo") - assert cast(Any, m3.nested) == "foo" - - m4 = NestedModel.construct(nested=[False]) - assert cast(Any, m4.nested) == [False] - - -def test_list_mismatched_type() -> None: - class NestedModel(BaseModel): - nested: List[str] - - m = NestedModel.construct(nested=False) - assert cast(Any, m.nested) is False - - -def test_raw_dictionary() -> None: - class NestedModel(BaseModel): - nested: Dict[str, str] - - m = NestedModel.construct(nested={"hello": "world"}) - assert m.nested == {"hello": "world"} - - # mismatched types - m = NestedModel.construct(nested=False) - assert cast(Any, m.nested) is False - - -def test_nested_dictionary_model() -> None: - class NestedModel(BaseModel): - nested: Dict[str, BasicModel] - - m = NestedModel.construct(nested={"hello": {"foo": "bar"}}) - assert isinstance(m.nested, dict) - assert m.nested["hello"].foo == "bar" - - # mismatched types - m = NestedModel.construct(nested={"hello": False}) - assert cast(Any, m.nested["hello"]) is False - - -def test_unknown_fields() -> None: - m1 = BasicModel.construct(foo="foo", unknown=1) - assert m1.foo == "foo" - assert cast(Any, m1).unknown == 1 - - m2 = BasicModel.construct(foo="foo", unknown={"foo_bar": True}) - assert m2.foo == "foo" - assert cast(Any, m2).unknown == {"foo_bar": True} - - assert model_dump(m2) == {"foo": "foo", "unknown": {"foo_bar": True}} - - -def test_strict_validation_unknown_fields() -> None: - class Model(BaseModel): - foo: str - - model = parse_obj(Model, dict(foo="hello!", user="Robert")) - assert model.foo == "hello!" - assert cast(Any, model).user == "Robert" - - assert model_dump(model) == {"foo": "hello!", "user": "Robert"} - - -def test_aliases() -> None: - class Model(BaseModel): - my_field: int = Field(alias="myField") - - m = Model.construct(myField=1) - assert m.my_field == 1 - - # mismatched types - m = Model.construct(myField={"hello": False}) - assert cast(Any, m.my_field) == {"hello": False} - - -def test_repr() -> None: - model = BasicModel(foo="bar") - assert str(model) == "BasicModel(foo='bar')" - assert repr(model) == "BasicModel(foo='bar')" - - -def test_repr_nested_model() -> None: - class Child(BaseModel): - name: str - age: int - - class Parent(BaseModel): - name: str - child: Child - - model = Parent(name="Robert", child=Child(name="Foo", age=5)) - assert str(model) == "Parent(name='Robert', child=Child(name='Foo', age=5))" - assert repr(model) == "Parent(name='Robert', child=Child(name='Foo', age=5))" - - -def test_optional_list() -> None: - class Submodel(BaseModel): - name: str - - class Model(BaseModel): - items: Optional[List[Submodel]] - - m = Model.construct(items=None) - assert m.items is None - - m = Model.construct(items=[]) - assert m.items == [] - - m = Model.construct(items=[{"name": "Robert"}]) - assert m.items is not None - assert len(m.items) == 1 - assert m.items[0].name == "Robert" - - -def test_nested_union_of_models() -> None: - class Submodel1(BaseModel): - bar: bool - - class Submodel2(BaseModel): - thing: str - - class Model(BaseModel): - foo: Union[Submodel1, Submodel2] - - m = Model.construct(foo={"thing": "hello"}) - assert isinstance(m.foo, Submodel2) - assert m.foo.thing == "hello" - - -def test_nested_union_of_mixed_types() -> None: - class Submodel1(BaseModel): - bar: bool - - class Model(BaseModel): - foo: Union[Submodel1, Literal[True], Literal["CARD_HOLDER"]] - - m = Model.construct(foo=True) - assert m.foo is True - - m = Model.construct(foo="CARD_HOLDER") - assert m.foo == "CARD_HOLDER" - - m = Model.construct(foo={"bar": False}) - assert isinstance(m.foo, Submodel1) - assert m.foo.bar is False - - -def test_nested_union_multiple_variants() -> None: - class Submodel1(BaseModel): - bar: bool - - class Submodel2(BaseModel): - thing: str - - class Submodel3(BaseModel): - foo: int - - class Model(BaseModel): - foo: Union[Submodel1, Submodel2, None, Submodel3] - - m = Model.construct(foo={"thing": "hello"}) - assert isinstance(m.foo, Submodel2) - assert m.foo.thing == "hello" - - m = Model.construct(foo=None) - assert m.foo is None - - m = Model.construct() - assert m.foo is None - - m = Model.construct(foo={"foo": "1"}) - assert isinstance(m.foo, Submodel3) - assert m.foo.foo == 1 - - -def test_nested_union_invalid_data() -> None: - class Submodel1(BaseModel): - level: int - - class Submodel2(BaseModel): - name: str - - class Model(BaseModel): - foo: Union[Submodel1, Submodel2] - - m = Model.construct(foo=True) - assert cast(bool, m.foo) is True - - m = Model.construct(foo={"name": 3}) - if PYDANTIC_V1: - assert isinstance(m.foo, Submodel2) - assert m.foo.name == "3" - else: - assert isinstance(m.foo, Submodel1) - assert m.foo.name == 3 # type: ignore - - -def test_list_of_unions() -> None: - class Submodel1(BaseModel): - level: int - - class Submodel2(BaseModel): - name: str - - class Model(BaseModel): - items: List[Union[Submodel1, Submodel2]] - - m = Model.construct(items=[{"level": 1}, {"name": "Robert"}]) - assert len(m.items) == 2 - assert isinstance(m.items[0], Submodel1) - assert m.items[0].level == 1 - assert isinstance(m.items[1], Submodel2) - assert m.items[1].name == "Robert" - - m = Model.construct(items=[{"level": -1}, 156]) - assert len(m.items) == 2 - assert isinstance(m.items[0], Submodel1) - assert m.items[0].level == -1 - assert cast(Any, m.items[1]) == 156 - - -def test_union_of_lists() -> None: - class SubModel1(BaseModel): - level: int - - class SubModel2(BaseModel): - name: str - - class Model(BaseModel): - items: Union[List[SubModel1], List[SubModel2]] - - # with one valid entry - m = Model.construct(items=[{"name": "Robert"}]) - assert len(m.items) == 1 - assert isinstance(m.items[0], SubModel2) - assert m.items[0].name == "Robert" - - # with two entries pointing to different types - m = Model.construct(items=[{"level": 1}, {"name": "Robert"}]) - assert len(m.items) == 2 - assert isinstance(m.items[0], SubModel1) - assert m.items[0].level == 1 - assert isinstance(m.items[1], SubModel1) - assert cast(Any, m.items[1]).name == "Robert" - - # with two entries pointing to *completely* different types - m = Model.construct(items=[{"level": -1}, 156]) - assert len(m.items) == 2 - assert isinstance(m.items[0], SubModel1) - assert m.items[0].level == -1 - assert cast(Any, m.items[1]) == 156 - - -def test_dict_of_union() -> None: - class SubModel1(BaseModel): - name: str - - class SubModel2(BaseModel): - foo: str - - class Model(BaseModel): - data: Dict[str, Union[SubModel1, SubModel2]] - - m = Model.construct(data={"hello": {"name": "there"}, "foo": {"foo": "bar"}}) - assert len(list(m.data.keys())) == 2 - assert isinstance(m.data["hello"], SubModel1) - assert m.data["hello"].name == "there" - assert isinstance(m.data["foo"], SubModel2) - assert m.data["foo"].foo == "bar" - - # TODO: test mismatched type - - -def test_double_nested_union() -> None: - class SubModel1(BaseModel): - name: str - - class SubModel2(BaseModel): - bar: str - - class Model(BaseModel): - data: Dict[str, List[Union[SubModel1, SubModel2]]] - - m = Model.construct(data={"foo": [{"bar": "baz"}, {"name": "Robert"}]}) - assert len(m.data["foo"]) == 2 - - entry1 = m.data["foo"][0] - assert isinstance(entry1, SubModel2) - assert entry1.bar == "baz" - - entry2 = m.data["foo"][1] - assert isinstance(entry2, SubModel1) - assert entry2.name == "Robert" - - # TODO: test mismatched type - - -def test_union_of_dict() -> None: - class SubModel1(BaseModel): - name: str - - class SubModel2(BaseModel): - foo: str - - class Model(BaseModel): - data: Union[Dict[str, SubModel1], Dict[str, SubModel2]] - - m = Model.construct(data={"hello": {"name": "there"}, "foo": {"foo": "bar"}}) - assert len(list(m.data.keys())) == 2 - assert isinstance(m.data["hello"], SubModel1) - assert m.data["hello"].name == "there" - assert isinstance(m.data["foo"], SubModel1) - assert cast(Any, m.data["foo"]).foo == "bar" - - -def test_iso8601_datetime() -> None: - class Model(BaseModel): - created_at: datetime - - expected = datetime(2019, 12, 27, 18, 11, 19, 117000, tzinfo=timezone.utc) - - if PYDANTIC_V1: - expected_json = '{"created_at": "2019-12-27T18:11:19.117000+00:00"}' - else: - expected_json = '{"created_at":"2019-12-27T18:11:19.117000Z"}' - - model = Model.construct(created_at="2019-12-27T18:11:19.117Z") - assert model.created_at == expected - assert model_json(model) == expected_json - - model = parse_obj(Model, dict(created_at="2019-12-27T18:11:19.117Z")) - assert model.created_at == expected - assert model_json(model) == expected_json - - -def test_does_not_coerce_int() -> None: - class Model(BaseModel): - bar: int - - assert Model.construct(bar=1).bar == 1 - assert Model.construct(bar=10.9).bar == 10.9 - assert Model.construct(bar="19").bar == "19" # type: ignore[comparison-overlap] - assert Model.construct(bar=False).bar is False - - -def test_int_to_float_safe_conversion() -> None: - class Model(BaseModel): - float_field: float - - m = Model.construct(float_field=10) - assert m.float_field == 10.0 - assert isinstance(m.float_field, float) - - m = Model.construct(float_field=10.12) - assert m.float_field == 10.12 - assert isinstance(m.float_field, float) - - # number too big - m = Model.construct(float_field=2**53 + 1) - assert m.float_field == 2**53 + 1 - assert isinstance(m.float_field, int) - - -def test_deprecated_alias() -> None: - class Model(BaseModel): - resource_id: str = Field(alias="model_id") - - @property - def model_id(self) -> str: - return self.resource_id - - m = Model.construct(model_id="id") - assert m.model_id == "id" - assert m.resource_id == "id" - assert m.resource_id is m.model_id - - m = parse_obj(Model, {"model_id": "id"}) - assert m.model_id == "id" - assert m.resource_id == "id" - assert m.resource_id is m.model_id - - -def test_omitted_fields() -> None: - class Model(BaseModel): - resource_id: Optional[str] = None - - m = Model.construct() - assert m.resource_id is None - assert "resource_id" not in m.model_fields_set - - m = Model.construct(resource_id=None) - assert m.resource_id is None - assert "resource_id" in m.model_fields_set - - m = Model.construct(resource_id="foo") - assert m.resource_id == "foo" - assert "resource_id" in m.model_fields_set - - -def test_to_dict() -> None: - class Model(BaseModel): - foo: Optional[str] = Field(alias="FOO", default=None) - - m = Model(FOO="hello") - assert m.to_dict() == {"FOO": "hello"} - assert m.to_dict(use_api_names=False) == {"foo": "hello"} - - m2 = Model() - assert m2.to_dict() == {} - assert m2.to_dict(exclude_unset=False) == {"FOO": None} - assert m2.to_dict(exclude_unset=False, exclude_none=True) == {} - assert m2.to_dict(exclude_unset=False, exclude_defaults=True) == {} - - m3 = Model(FOO=None) - assert m3.to_dict() == {"FOO": None} - assert m3.to_dict(exclude_none=True) == {} - assert m3.to_dict(exclude_defaults=True) == {} - - class Model2(BaseModel): - created_at: datetime - - time_str = "2024-03-21T11:39:01.275859" - m4 = Model2.construct(created_at=time_str) - assert m4.to_dict(mode="python") == {"created_at": datetime.fromisoformat(time_str)} - assert m4.to_dict(mode="json") == {"created_at": time_str} - - if PYDANTIC_V1: - with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): - m.to_dict(warnings=False) - - -def test_forwards_compat_model_dump_method() -> None: - class Model(BaseModel): - foo: Optional[str] = Field(alias="FOO", default=None) - - m = Model(FOO="hello") - assert m.model_dump() == {"foo": "hello"} - assert m.model_dump(include={"bar"}) == {} - assert m.model_dump(exclude={"foo"}) == {} - assert m.model_dump(by_alias=True) == {"FOO": "hello"} - - m2 = Model() - assert m2.model_dump() == {"foo": None} - assert m2.model_dump(exclude_unset=True) == {} - assert m2.model_dump(exclude_none=True) == {} - assert m2.model_dump(exclude_defaults=True) == {} - - m3 = Model(FOO=None) - assert m3.model_dump() == {"foo": None} - assert m3.model_dump(exclude_none=True) == {} - - if PYDANTIC_V1: - with pytest.raises(ValueError, match="round_trip is only supported in Pydantic v2"): - m.model_dump(round_trip=True) - - with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): - m.model_dump(warnings=False) - - -def test_compat_method_no_error_for_warnings() -> None: - class Model(BaseModel): - foo: Optional[str] - - m = Model(foo="hello") - assert isinstance(model_dump(m, warnings=False), dict) - - -def test_to_json() -> None: - class Model(BaseModel): - foo: Optional[str] = Field(alias="FOO", default=None) - - m = Model(FOO="hello") - assert json.loads(m.to_json()) == {"FOO": "hello"} - assert json.loads(m.to_json(use_api_names=False)) == {"foo": "hello"} - - if PYDANTIC_V1: - assert m.to_json(indent=None) == '{"FOO": "hello"}' - else: - assert m.to_json(indent=None) == '{"FOO":"hello"}' - - m2 = Model() - assert json.loads(m2.to_json()) == {} - assert json.loads(m2.to_json(exclude_unset=False)) == {"FOO": None} - assert json.loads(m2.to_json(exclude_unset=False, exclude_none=True)) == {} - assert json.loads(m2.to_json(exclude_unset=False, exclude_defaults=True)) == {} - - m3 = Model(FOO=None) - assert json.loads(m3.to_json()) == {"FOO": None} - assert json.loads(m3.to_json(exclude_none=True)) == {} - - if PYDANTIC_V1: - with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): - m.to_json(warnings=False) - - -def test_forwards_compat_model_dump_json_method() -> None: - class Model(BaseModel): - foo: Optional[str] = Field(alias="FOO", default=None) - - m = Model(FOO="hello") - assert json.loads(m.model_dump_json()) == {"foo": "hello"} - assert json.loads(m.model_dump_json(include={"bar"})) == {} - assert json.loads(m.model_dump_json(include={"foo"})) == {"foo": "hello"} - assert json.loads(m.model_dump_json(by_alias=True)) == {"FOO": "hello"} - - assert m.model_dump_json(indent=2) == '{\n "foo": "hello"\n}' - - m2 = Model() - assert json.loads(m2.model_dump_json()) == {"foo": None} - assert json.loads(m2.model_dump_json(exclude_unset=True)) == {} - assert json.loads(m2.model_dump_json(exclude_none=True)) == {} - assert json.loads(m2.model_dump_json(exclude_defaults=True)) == {} - - m3 = Model(FOO=None) - assert json.loads(m3.model_dump_json()) == {"foo": None} - assert json.loads(m3.model_dump_json(exclude_none=True)) == {} - - if PYDANTIC_V1: - with pytest.raises(ValueError, match="round_trip is only supported in Pydantic v2"): - m.model_dump_json(round_trip=True) - - with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): - m.model_dump_json(warnings=False) - - -def test_type_compat() -> None: - # our model type can be assigned to Pydantic's model type - - def takes_pydantic(model: pydantic.BaseModel) -> None: # noqa: ARG001 - ... - - class OurModel(BaseModel): - foo: Optional[str] = None - - takes_pydantic(OurModel()) - - -def test_annotated_types() -> None: - class Model(BaseModel): - value: str - - m = construct_type( - value={"value": "foo"}, - type_=cast(Any, Annotated[Model, "random metadata"]), - ) - assert isinstance(m, Model) - assert m.value == "foo" - - -def test_discriminated_unions_invalid_data() -> None: - class A(BaseModel): - type: Literal["a"] - - data: str - - class B(BaseModel): - type: Literal["b"] - - data: int - - m = construct_type( - value={"type": "b", "data": "foo"}, - type_=cast(Any, Annotated[Union[A, B], PropertyInfo(discriminator="type")]), - ) - assert isinstance(m, B) - assert m.type == "b" - assert m.data == "foo" # type: ignore[comparison-overlap] - - m = construct_type( - value={"type": "a", "data": 100}, - type_=cast(Any, Annotated[Union[A, B], PropertyInfo(discriminator="type")]), - ) - assert isinstance(m, A) - assert m.type == "a" - if PYDANTIC_V1: - # pydantic v1 automatically converts inputs to strings - # if the expected type is a str - assert m.data == "100" - else: - assert m.data == 100 # type: ignore[comparison-overlap] - - -def test_discriminated_unions_unknown_variant() -> None: - class A(BaseModel): - type: Literal["a"] - - data: str - - class B(BaseModel): - type: Literal["b"] - - data: int - - m = construct_type( - value={"type": "c", "data": None, "new_thing": "bar"}, - type_=cast(Any, Annotated[Union[A, B], PropertyInfo(discriminator="type")]), - ) - - # just chooses the first variant - assert isinstance(m, A) - assert m.type == "c" # type: ignore[comparison-overlap] - assert m.data == None # type: ignore[unreachable] - assert m.new_thing == "bar" - - -def test_discriminated_unions_invalid_data_nested_unions() -> None: - class A(BaseModel): - type: Literal["a"] - - data: str - - class B(BaseModel): - type: Literal["b"] - - data: int - - class C(BaseModel): - type: Literal["c"] - - data: bool - - m = construct_type( - value={"type": "b", "data": "foo"}, - type_=cast(Any, Annotated[Union[Union[A, B], C], PropertyInfo(discriminator="type")]), - ) - assert isinstance(m, B) - assert m.type == "b" - assert m.data == "foo" # type: ignore[comparison-overlap] - - m = construct_type( - value={"type": "c", "data": "foo"}, - type_=cast(Any, Annotated[Union[Union[A, B], C], PropertyInfo(discriminator="type")]), - ) - assert isinstance(m, C) - assert m.type == "c" - assert m.data == "foo" # type: ignore[comparison-overlap] - - -def test_discriminated_unions_with_aliases_invalid_data() -> None: - class A(BaseModel): - foo_type: Literal["a"] = Field(alias="type") - - data: str - - class B(BaseModel): - foo_type: Literal["b"] = Field(alias="type") - - data: int - - m = construct_type( - value={"type": "b", "data": "foo"}, - type_=cast(Any, Annotated[Union[A, B], PropertyInfo(discriminator="foo_type")]), - ) - assert isinstance(m, B) - assert m.foo_type == "b" - assert m.data == "foo" # type: ignore[comparison-overlap] - - m = construct_type( - value={"type": "a", "data": 100}, - type_=cast(Any, Annotated[Union[A, B], PropertyInfo(discriminator="foo_type")]), - ) - assert isinstance(m, A) - assert m.foo_type == "a" - if PYDANTIC_V1: - # pydantic v1 automatically converts inputs to strings - # if the expected type is a str - assert m.data == "100" - else: - assert m.data == 100 # type: ignore[comparison-overlap] - - -def test_discriminated_unions_overlapping_discriminators_invalid_data() -> None: - class A(BaseModel): - type: Literal["a"] - - data: bool - - class B(BaseModel): - type: Literal["a"] - - data: int - - m = construct_type( - value={"type": "a", "data": "foo"}, - type_=cast(Any, Annotated[Union[A, B], PropertyInfo(discriminator="type")]), - ) - assert isinstance(m, B) - assert m.type == "a" - assert m.data == "foo" # type: ignore[comparison-overlap] - - -def test_discriminated_unions_invalid_data_uses_cache() -> None: - class A(BaseModel): - type: Literal["a"] - - data: str - - class B(BaseModel): - type: Literal["b"] - - data: int - - UnionType = cast(Any, Union[A, B]) - - assert not DISCRIMINATOR_CACHE.get(UnionType) - - m = construct_type( - value={"type": "b", "data": "foo"}, type_=cast(Any, Annotated[UnionType, PropertyInfo(discriminator="type")]) - ) - assert isinstance(m, B) - assert m.type == "b" - assert m.data == "foo" # type: ignore[comparison-overlap] - - discriminator = DISCRIMINATOR_CACHE.get(UnionType) - assert discriminator is not None - - m = construct_type( - value={"type": "b", "data": "foo"}, type_=cast(Any, Annotated[UnionType, PropertyInfo(discriminator="type")]) - ) - assert isinstance(m, B) - assert m.type == "b" - assert m.data == "foo" # type: ignore[comparison-overlap] - - # if the discriminator details object stays the same between invocations then - # we hit the cache - assert DISCRIMINATOR_CACHE.get(UnionType) is discriminator - - -@pytest.mark.skipif(PYDANTIC_V1, reason="TypeAliasType is not supported in Pydantic v1") -def test_type_alias_type() -> None: - Alias = TypeAliasType("Alias", str) # pyright: ignore - - class Model(BaseModel): - alias: Alias - union: Union[int, Alias] - - m = construct_type(value={"alias": "foo", "union": "bar"}, type_=Model) - assert isinstance(m, Model) - assert isinstance(m.alias, str) - assert m.alias == "foo" - assert isinstance(m.union, str) - assert m.union == "bar" - - -@pytest.mark.skipif(PYDANTIC_V1, reason="TypeAliasType is not supported in Pydantic v1") -def test_field_named_cls() -> None: - class Model(BaseModel): - cls: str - - m = construct_type(value={"cls": "foo"}, type_=Model) - assert isinstance(m, Model) - assert isinstance(m.cls, str) - - -def test_discriminated_union_case() -> None: - class A(BaseModel): - type: Literal["a"] - - data: bool - - class B(BaseModel): - type: Literal["b"] - - data: List[Union[A, object]] - - class ModelA(BaseModel): - type: Literal["modelA"] - - data: int - - class ModelB(BaseModel): - type: Literal["modelB"] - - required: str - - data: Union[A, B] - - # when constructing ModelA | ModelB, value data doesn't match ModelB exactly - missing `required` - m = construct_type( - value={"type": "modelB", "data": {"type": "a", "data": True}}, - type_=cast(Any, Annotated[Union[ModelA, ModelB], PropertyInfo(discriminator="type")]), - ) - - assert isinstance(m, ModelB) - - -def test_nested_discriminated_union() -> None: - class InnerType1(BaseModel): - type: Literal["type_1"] - - class InnerModel(BaseModel): - inner_value: str - - class InnerType2(BaseModel): - type: Literal["type_2"] - some_inner_model: InnerModel - - class Type1(BaseModel): - base_type: Literal["base_type_1"] - value: Annotated[ - Union[ - InnerType1, - InnerType2, - ], - PropertyInfo(discriminator="type"), - ] - - class Type2(BaseModel): - base_type: Literal["base_type_2"] - - T = Annotated[ - Union[ - Type1, - Type2, - ], - PropertyInfo(discriminator="base_type"), - ] - - model = construct_type( - type_=T, - value={ - "base_type": "base_type_1", - "value": { - "type": "type_2", - }, - }, - ) - assert isinstance(model, Type1) - assert isinstance(model.value, InnerType2) - - -@pytest.mark.skipif(PYDANTIC_V1, reason="this is only supported in pydantic v2 for now") -def test_extra_properties() -> None: - class Item(BaseModel): - prop: int - - class Model(BaseModel): - __pydantic_extra__: Dict[str, Item] = Field(init=False) # pyright: ignore[reportIncompatibleVariableOverride] - - other: str - - if TYPE_CHECKING: - - def __getattr__(self, attr: str) -> Item: ... - - model = construct_type( - type_=Model, - value={ - "a": {"prop": 1}, - "other": "foo", - }, - ) - assert isinstance(model, Model) - assert model.a.prop == 1 - assert isinstance(model.a, Item) - assert model.other == "foo" diff --git a/tests/test_qs.py b/tests/test_qs.py deleted file mode 100644 index c6d26e25c..000000000 --- a/tests/test_qs.py +++ /dev/null @@ -1,78 +0,0 @@ -from typing import Any, cast -from functools import partial -from urllib.parse import unquote - -import pytest - -from metronome._qs import Querystring, stringify - - -def test_empty() -> None: - assert stringify({}) == "" - assert stringify({"a": {}}) == "" - assert stringify({"a": {"b": {"c": {}}}}) == "" - - -def test_basic() -> None: - assert stringify({"a": 1}) == "a=1" - assert stringify({"a": "b"}) == "a=b" - assert stringify({"a": True}) == "a=true" - assert stringify({"a": False}) == "a=false" - assert stringify({"a": 1.23456}) == "a=1.23456" - assert stringify({"a": None}) == "" - - -@pytest.mark.parametrize("method", ["class", "function"]) -def test_nested_dotted(method: str) -> None: - if method == "class": - serialise = Querystring(nested_format="dots").stringify - else: - serialise = partial(stringify, nested_format="dots") - - assert unquote(serialise({"a": {"b": "c"}})) == "a.b=c" - assert unquote(serialise({"a": {"b": "c", "d": "e", "f": "g"}})) == "a.b=c&a.d=e&a.f=g" - assert unquote(serialise({"a": {"b": {"c": {"d": "e"}}}})) == "a.b.c.d=e" - assert unquote(serialise({"a": {"b": True}})) == "a.b=true" - - -def test_nested_brackets() -> None: - assert unquote(stringify({"a": {"b": "c"}})) == "a[b]=c" - assert unquote(stringify({"a": {"b": "c", "d": "e", "f": "g"}})) == "a[b]=c&a[d]=e&a[f]=g" - assert unquote(stringify({"a": {"b": {"c": {"d": "e"}}}})) == "a[b][c][d]=e" - assert unquote(stringify({"a": {"b": True}})) == "a[b]=true" - - -@pytest.mark.parametrize("method", ["class", "function"]) -def test_array_comma(method: str) -> None: - if method == "class": - serialise = Querystring(array_format="comma").stringify - else: - serialise = partial(stringify, array_format="comma") - - assert unquote(serialise({"in": ["foo", "bar"]})) == "in=foo,bar" - assert unquote(serialise({"a": {"b": [True, False]}})) == "a[b]=true,false" - assert unquote(serialise({"a": {"b": [True, False, None, True]}})) == "a[b]=true,false,true" - - -def test_array_repeat() -> None: - assert unquote(stringify({"in": ["foo", "bar"]})) == "in=foo&in=bar" - assert unquote(stringify({"a": {"b": [True, False]}})) == "a[b]=true&a[b]=false" - assert unquote(stringify({"a": {"b": [True, False, None, True]}})) == "a[b]=true&a[b]=false&a[b]=true" - assert unquote(stringify({"in": ["foo", {"b": {"c": ["d", "e"]}}]})) == "in=foo&in[b][c]=d&in[b][c]=e" - - -@pytest.mark.parametrize("method", ["class", "function"]) -def test_array_brackets(method: str) -> None: - if method == "class": - serialise = Querystring(array_format="brackets").stringify - else: - serialise = partial(stringify, array_format="brackets") - - assert unquote(serialise({"in": ["foo", "bar"]})) == "in[]=foo&in[]=bar" - assert unquote(serialise({"a": {"b": [True, False]}})) == "a[b][]=true&a[b][]=false" - assert unquote(serialise({"a": {"b": [True, False, None, True]}})) == "a[b][]=true&a[b][]=false&a[b][]=true" - - -def test_unknown_array_format() -> None: - with pytest.raises(NotImplementedError, match="Unknown array_format value: foo, choose from comma, repeat"): - stringify({"a": ["foo", "bar"]}, array_format=cast(Any, "foo")) diff --git a/tests/test_required_args.py b/tests/test_required_args.py deleted file mode 100644 index bcdca156f..000000000 --- a/tests/test_required_args.py +++ /dev/null @@ -1,111 +0,0 @@ -from __future__ import annotations - -import pytest - -from metronome._utils import required_args - - -def test_too_many_positional_params() -> None: - @required_args(["a"]) - def foo(a: str | None = None) -> str | None: - return a - - with pytest.raises(TypeError, match=r"foo\(\) takes 1 argument\(s\) but 2 were given"): - foo("a", "b") # type: ignore - - -def test_positional_param() -> None: - @required_args(["a"]) - def foo(a: str | None = None) -> str | None: - return a - - assert foo("a") == "a" - assert foo(None) is None - assert foo(a="b") == "b" - - with pytest.raises(TypeError, match="Missing required argument: 'a'"): - foo() - - -def test_keyword_only_param() -> None: - @required_args(["a"]) - def foo(*, a: str | None = None) -> str | None: - return a - - assert foo(a="a") == "a" - assert foo(a=None) is None - assert foo(a="b") == "b" - - with pytest.raises(TypeError, match="Missing required argument: 'a'"): - foo() - - -def test_multiple_params() -> None: - @required_args(["a", "b", "c"]) - def foo(a: str = "", *, b: str = "", c: str = "") -> str | None: - return f"{a} {b} {c}" - - assert foo(a="a", b="b", c="c") == "a b c" - - error_message = r"Missing required arguments.*" - - with pytest.raises(TypeError, match=error_message): - foo() - - with pytest.raises(TypeError, match=error_message): - foo(a="a") - - with pytest.raises(TypeError, match=error_message): - foo(b="b") - - with pytest.raises(TypeError, match=error_message): - foo(c="c") - - with pytest.raises(TypeError, match=r"Missing required argument: 'a'"): - foo(b="a", c="c") - - with pytest.raises(TypeError, match=r"Missing required argument: 'b'"): - foo("a", c="c") - - -def test_multiple_variants() -> None: - @required_args(["a"], ["b"]) - def foo(*, a: str | None = None, b: str | None = None) -> str | None: - return a if a is not None else b - - assert foo(a="foo") == "foo" - assert foo(b="bar") == "bar" - assert foo(a=None) is None - assert foo(b=None) is None - - # TODO: this error message could probably be improved - with pytest.raises( - TypeError, - match=r"Missing required arguments; Expected either \('a'\) or \('b'\) arguments to be given", - ): - foo() - - -def test_multiple_params_multiple_variants() -> None: - @required_args(["a", "b"], ["c"]) - def foo(*, a: str | None = None, b: str | None = None, c: str | None = None) -> str | None: - if a is not None: - return a - if b is not None: - return b - return c - - error_message = r"Missing required arguments; Expected either \('a' and 'b'\) or \('c'\) arguments to be given" - - with pytest.raises(TypeError, match=error_message): - foo(a="foo") - - with pytest.raises(TypeError, match=error_message): - foo(b="bar") - - with pytest.raises(TypeError, match=error_message): - foo() - - assert foo(a=None, b="bar") == "bar" - assert foo(c=None) is None - assert foo(c="foo") == "foo" diff --git a/tests/test_response.py b/tests/test_response.py deleted file mode 100644 index 64eb64ad6..000000000 --- a/tests/test_response.py +++ /dev/null @@ -1,277 +0,0 @@ -import json -from typing import Any, List, Union, cast -from typing_extensions import Annotated - -import httpx -import pytest -import pydantic - -from metronome import BaseModel, Metronome, AsyncMetronome -from metronome._response import ( - APIResponse, - BaseAPIResponse, - AsyncAPIResponse, - BinaryAPIResponse, - AsyncBinaryAPIResponse, - extract_response_type, -) -from metronome._streaming import Stream -from metronome._base_client import FinalRequestOptions - - -class ConcreteBaseAPIResponse(APIResponse[bytes]): ... - - -class ConcreteAPIResponse(APIResponse[List[str]]): ... - - -class ConcreteAsyncAPIResponse(APIResponse[httpx.Response]): ... - - -def test_extract_response_type_direct_classes() -> None: - assert extract_response_type(BaseAPIResponse[str]) == str - assert extract_response_type(APIResponse[str]) == str - assert extract_response_type(AsyncAPIResponse[str]) == str - - -def test_extract_response_type_direct_class_missing_type_arg() -> None: - with pytest.raises( - RuntimeError, - match="Expected type to have a type argument at index 0 but it did not", - ): - extract_response_type(AsyncAPIResponse) - - -def test_extract_response_type_concrete_subclasses() -> None: - assert extract_response_type(ConcreteBaseAPIResponse) == bytes - assert extract_response_type(ConcreteAPIResponse) == List[str] - assert extract_response_type(ConcreteAsyncAPIResponse) == httpx.Response - - -def test_extract_response_type_binary_response() -> None: - assert extract_response_type(BinaryAPIResponse) == bytes - assert extract_response_type(AsyncBinaryAPIResponse) == bytes - - -class PydanticModel(pydantic.BaseModel): ... - - -def test_response_parse_mismatched_basemodel(client: Metronome) -> None: - response = APIResponse( - raw=httpx.Response(200, content=b"foo"), - client=client, - stream=False, - stream_cls=None, - cast_to=str, - options=FinalRequestOptions.construct(method="get", url="/foo"), - ) - - with pytest.raises( - TypeError, - match="Pydantic models must subclass our base model type, e.g. `from metronome import BaseModel`", - ): - response.parse(to=PydanticModel) - - -@pytest.mark.asyncio -async def test_async_response_parse_mismatched_basemodel(async_client: AsyncMetronome) -> None: - response = AsyncAPIResponse( - raw=httpx.Response(200, content=b"foo"), - client=async_client, - stream=False, - stream_cls=None, - cast_to=str, - options=FinalRequestOptions.construct(method="get", url="/foo"), - ) - - with pytest.raises( - TypeError, - match="Pydantic models must subclass our base model type, e.g. `from metronome import BaseModel`", - ): - await response.parse(to=PydanticModel) - - -def test_response_parse_custom_stream(client: Metronome) -> None: - response = APIResponse( - raw=httpx.Response(200, content=b"foo"), - client=client, - stream=True, - stream_cls=None, - cast_to=str, - options=FinalRequestOptions.construct(method="get", url="/foo"), - ) - - stream = response.parse(to=Stream[int]) - assert stream._cast_to == int - - -@pytest.mark.asyncio -async def test_async_response_parse_custom_stream(async_client: AsyncMetronome) -> None: - response = AsyncAPIResponse( - raw=httpx.Response(200, content=b"foo"), - client=async_client, - stream=True, - stream_cls=None, - cast_to=str, - options=FinalRequestOptions.construct(method="get", url="/foo"), - ) - - stream = await response.parse(to=Stream[int]) - assert stream._cast_to == int - - -class CustomModel(BaseModel): - foo: str - bar: int - - -def test_response_parse_custom_model(client: Metronome) -> None: - response = APIResponse( - raw=httpx.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})), - client=client, - stream=False, - stream_cls=None, - cast_to=str, - options=FinalRequestOptions.construct(method="get", url="/foo"), - ) - - obj = response.parse(to=CustomModel) - assert obj.foo == "hello!" - assert obj.bar == 2 - - -@pytest.mark.asyncio -async def test_async_response_parse_custom_model(async_client: AsyncMetronome) -> None: - response = AsyncAPIResponse( - raw=httpx.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})), - client=async_client, - stream=False, - stream_cls=None, - cast_to=str, - options=FinalRequestOptions.construct(method="get", url="/foo"), - ) - - obj = await response.parse(to=CustomModel) - assert obj.foo == "hello!" - assert obj.bar == 2 - - -def test_response_parse_annotated_type(client: Metronome) -> None: - response = APIResponse( - raw=httpx.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})), - client=client, - stream=False, - stream_cls=None, - cast_to=str, - options=FinalRequestOptions.construct(method="get", url="/foo"), - ) - - obj = response.parse( - to=cast("type[CustomModel]", Annotated[CustomModel, "random metadata"]), - ) - assert obj.foo == "hello!" - assert obj.bar == 2 - - -async def test_async_response_parse_annotated_type(async_client: AsyncMetronome) -> None: - response = AsyncAPIResponse( - raw=httpx.Response(200, content=json.dumps({"foo": "hello!", "bar": 2})), - client=async_client, - stream=False, - stream_cls=None, - cast_to=str, - options=FinalRequestOptions.construct(method="get", url="/foo"), - ) - - obj = await response.parse( - to=cast("type[CustomModel]", Annotated[CustomModel, "random metadata"]), - ) - assert obj.foo == "hello!" - assert obj.bar == 2 - - -@pytest.mark.parametrize( - "content, expected", - [ - ("false", False), - ("true", True), - ("False", False), - ("True", True), - ("TrUe", True), - ("FalSe", False), - ], -) -def test_response_parse_bool(client: Metronome, content: str, expected: bool) -> None: - response = APIResponse( - raw=httpx.Response(200, content=content), - client=client, - stream=False, - stream_cls=None, - cast_to=str, - options=FinalRequestOptions.construct(method="get", url="/foo"), - ) - - result = response.parse(to=bool) - assert result is expected - - -@pytest.mark.parametrize( - "content, expected", - [ - ("false", False), - ("true", True), - ("False", False), - ("True", True), - ("TrUe", True), - ("FalSe", False), - ], -) -async def test_async_response_parse_bool(client: AsyncMetronome, content: str, expected: bool) -> None: - response = AsyncAPIResponse( - raw=httpx.Response(200, content=content), - client=client, - stream=False, - stream_cls=None, - cast_to=str, - options=FinalRequestOptions.construct(method="get", url="/foo"), - ) - - result = await response.parse(to=bool) - assert result is expected - - -class OtherModel(BaseModel): - a: str - - -@pytest.mark.parametrize("client", [False], indirect=True) # loose validation -def test_response_parse_expect_model_union_non_json_content(client: Metronome) -> None: - response = APIResponse( - raw=httpx.Response(200, content=b"foo", headers={"Content-Type": "application/text"}), - client=client, - stream=False, - stream_cls=None, - cast_to=str, - options=FinalRequestOptions.construct(method="get", url="/foo"), - ) - - obj = response.parse(to=cast(Any, Union[CustomModel, OtherModel])) - assert isinstance(obj, str) - assert obj == "foo" - - -@pytest.mark.asyncio -@pytest.mark.parametrize("async_client", [False], indirect=True) # loose validation -async def test_async_response_parse_expect_model_union_non_json_content(async_client: AsyncMetronome) -> None: - response = AsyncAPIResponse( - raw=httpx.Response(200, content=b"foo", headers={"Content-Type": "application/text"}), - client=async_client, - stream=False, - stream_cls=None, - cast_to=str, - options=FinalRequestOptions.construct(method="get", url="/foo"), - ) - - obj = await response.parse(to=cast(Any, Union[CustomModel, OtherModel])) - assert isinstance(obj, str) - assert obj == "foo" diff --git a/tests/test_streaming.py b/tests/test_streaming.py deleted file mode 100644 index e73fe7fcb..000000000 --- a/tests/test_streaming.py +++ /dev/null @@ -1,248 +0,0 @@ -from __future__ import annotations - -from typing import Iterator, AsyncIterator - -import httpx -import pytest - -from metronome import Metronome, AsyncMetronome -from metronome._streaming import Stream, AsyncStream, ServerSentEvent - - -@pytest.mark.asyncio -@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) -async def test_basic(sync: bool, client: Metronome, async_client: AsyncMetronome) -> None: - def body() -> Iterator[bytes]: - yield b"event: completion\n" - yield b'data: {"foo":true}\n' - yield b"\n" - - iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) - - sse = await iter_next(iterator) - assert sse.event == "completion" - assert sse.json() == {"foo": True} - - await assert_empty_iter(iterator) - - -@pytest.mark.asyncio -@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) -async def test_data_missing_event(sync: bool, client: Metronome, async_client: AsyncMetronome) -> None: - def body() -> Iterator[bytes]: - yield b'data: {"foo":true}\n' - yield b"\n" - - iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) - - sse = await iter_next(iterator) - assert sse.event is None - assert sse.json() == {"foo": True} - - await assert_empty_iter(iterator) - - -@pytest.mark.asyncio -@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) -async def test_event_missing_data(sync: bool, client: Metronome, async_client: AsyncMetronome) -> None: - def body() -> Iterator[bytes]: - yield b"event: ping\n" - yield b"\n" - - iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) - - sse = await iter_next(iterator) - assert sse.event == "ping" - assert sse.data == "" - - await assert_empty_iter(iterator) - - -@pytest.mark.asyncio -@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) -async def test_multiple_events(sync: bool, client: Metronome, async_client: AsyncMetronome) -> None: - def body() -> Iterator[bytes]: - yield b"event: ping\n" - yield b"\n" - yield b"event: completion\n" - yield b"\n" - - iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) - - sse = await iter_next(iterator) - assert sse.event == "ping" - assert sse.data == "" - - sse = await iter_next(iterator) - assert sse.event == "completion" - assert sse.data == "" - - await assert_empty_iter(iterator) - - -@pytest.mark.asyncio -@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) -async def test_multiple_events_with_data(sync: bool, client: Metronome, async_client: AsyncMetronome) -> None: - def body() -> Iterator[bytes]: - yield b"event: ping\n" - yield b'data: {"foo":true}\n' - yield b"\n" - yield b"event: completion\n" - yield b'data: {"bar":false}\n' - yield b"\n" - - iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) - - sse = await iter_next(iterator) - assert sse.event == "ping" - assert sse.json() == {"foo": True} - - sse = await iter_next(iterator) - assert sse.event == "completion" - assert sse.json() == {"bar": False} - - await assert_empty_iter(iterator) - - -@pytest.mark.asyncio -@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) -async def test_multiple_data_lines_with_empty_line(sync: bool, client: Metronome, async_client: AsyncMetronome) -> None: - def body() -> Iterator[bytes]: - yield b"event: ping\n" - yield b"data: {\n" - yield b'data: "foo":\n' - yield b"data: \n" - yield b"data:\n" - yield b"data: true}\n" - yield b"\n\n" - - iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) - - sse = await iter_next(iterator) - assert sse.event == "ping" - assert sse.json() == {"foo": True} - assert sse.data == '{\n"foo":\n\n\ntrue}' - - await assert_empty_iter(iterator) - - -@pytest.mark.asyncio -@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) -async def test_data_json_escaped_double_new_line(sync: bool, client: Metronome, async_client: AsyncMetronome) -> None: - def body() -> Iterator[bytes]: - yield b"event: ping\n" - yield b'data: {"foo": "my long\\n\\ncontent"}' - yield b"\n\n" - - iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) - - sse = await iter_next(iterator) - assert sse.event == "ping" - assert sse.json() == {"foo": "my long\n\ncontent"} - - await assert_empty_iter(iterator) - - -@pytest.mark.asyncio -@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) -async def test_multiple_data_lines(sync: bool, client: Metronome, async_client: AsyncMetronome) -> None: - def body() -> Iterator[bytes]: - yield b"event: ping\n" - yield b"data: {\n" - yield b'data: "foo":\n' - yield b"data: true}\n" - yield b"\n\n" - - iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) - - sse = await iter_next(iterator) - assert sse.event == "ping" - assert sse.json() == {"foo": True} - - await assert_empty_iter(iterator) - - -@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) -async def test_special_new_line_character( - sync: bool, - client: Metronome, - async_client: AsyncMetronome, -) -> None: - def body() -> Iterator[bytes]: - yield b'data: {"content":" culpa"}\n' - yield b"\n" - yield b'data: {"content":" \xe2\x80\xa8"}\n' - yield b"\n" - yield b'data: {"content":"foo"}\n' - yield b"\n" - - iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) - - sse = await iter_next(iterator) - assert sse.event is None - assert sse.json() == {"content": " culpa"} - - sse = await iter_next(iterator) - assert sse.event is None - assert sse.json() == {"content": " 
"} - - sse = await iter_next(iterator) - assert sse.event is None - assert sse.json() == {"content": "foo"} - - await assert_empty_iter(iterator) - - -@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) -async def test_multi_byte_character_multiple_chunks( - sync: bool, - client: Metronome, - async_client: AsyncMetronome, -) -> None: - def body() -> Iterator[bytes]: - yield b'data: {"content":"' - # bytes taken from the string 'известни' and arbitrarily split - # so that some multi-byte characters span multiple chunks - yield b"\xd0" - yield b"\xb8\xd0\xb7\xd0" - yield b"\xb2\xd0\xb5\xd1\x81\xd1\x82\xd0\xbd\xd0\xb8" - yield b'"}\n' - yield b"\n" - - iterator = make_event_iterator(content=body(), sync=sync, client=client, async_client=async_client) - - sse = await iter_next(iterator) - assert sse.event is None - assert sse.json() == {"content": "известни"} - - -async def to_aiter(iter: Iterator[bytes]) -> AsyncIterator[bytes]: - for chunk in iter: - yield chunk - - -async def iter_next(iter: Iterator[ServerSentEvent] | AsyncIterator[ServerSentEvent]) -> ServerSentEvent: - if isinstance(iter, AsyncIterator): - return await iter.__anext__() - - return next(iter) - - -async def assert_empty_iter(iter: Iterator[ServerSentEvent] | AsyncIterator[ServerSentEvent]) -> None: - with pytest.raises((StopAsyncIteration, RuntimeError)): - await iter_next(iter) - - -def make_event_iterator( - content: Iterator[bytes], - *, - sync: bool, - client: Metronome, - async_client: AsyncMetronome, -) -> Iterator[ServerSentEvent] | AsyncIterator[ServerSentEvent]: - if sync: - return Stream(cast_to=object, client=client, response=httpx.Response(200, content=content))._iter_events() - - return AsyncStream( - cast_to=object, client=async_client, response=httpx.Response(200, content=to_aiter(content)) - )._iter_events() diff --git a/tests/test_transform.py b/tests/test_transform.py deleted file mode 100644 index b0bd9101c..000000000 --- a/tests/test_transform.py +++ /dev/null @@ -1,459 +0,0 @@ -from __future__ import annotations - -import io -import pathlib -from typing import Any, Dict, List, Union, TypeVar, Iterable, Optional, cast -from datetime import date, datetime -from typing_extensions import Required, Annotated, TypedDict - -import pytest - -from metronome._types import Base64FileInput, omit, not_given -from metronome._utils import ( - PropertyInfo, - transform as _transform, - parse_datetime, - async_transform as _async_transform, -) -from metronome._compat import PYDANTIC_V1 -from metronome._models import BaseModel - -_T = TypeVar("_T") - -SAMPLE_FILE_PATH = pathlib.Path(__file__).parent.joinpath("sample_file.txt") - - -async def transform( - data: _T, - expected_type: object, - use_async: bool, -) -> _T: - if use_async: - return await _async_transform(data, expected_type=expected_type) - - return _transform(data, expected_type=expected_type) - - -parametrize = pytest.mark.parametrize("use_async", [False, True], ids=["sync", "async"]) - - -class Foo1(TypedDict): - foo_bar: Annotated[str, PropertyInfo(alias="fooBar")] - - -@parametrize -@pytest.mark.asyncio -async def test_top_level_alias(use_async: bool) -> None: - assert await transform({"foo_bar": "hello"}, expected_type=Foo1, use_async=use_async) == {"fooBar": "hello"} - - -class Foo2(TypedDict): - bar: Bar2 - - -class Bar2(TypedDict): - this_thing: Annotated[int, PropertyInfo(alias="this__thing")] - baz: Annotated[Baz2, PropertyInfo(alias="Baz")] - - -class Baz2(TypedDict): - my_baz: Annotated[str, PropertyInfo(alias="myBaz")] - - -@parametrize -@pytest.mark.asyncio -async def test_recursive_typeddict(use_async: bool) -> None: - assert await transform({"bar": {"this_thing": 1}}, Foo2, use_async) == {"bar": {"this__thing": 1}} - assert await transform({"bar": {"baz": {"my_baz": "foo"}}}, Foo2, use_async) == {"bar": {"Baz": {"myBaz": "foo"}}} - - -class Foo3(TypedDict): - things: List[Bar3] - - -class Bar3(TypedDict): - my_field: Annotated[str, PropertyInfo(alias="myField")] - - -@parametrize -@pytest.mark.asyncio -async def test_list_of_typeddict(use_async: bool) -> None: - result = await transform({"things": [{"my_field": "foo"}, {"my_field": "foo2"}]}, Foo3, use_async) - assert result == {"things": [{"myField": "foo"}, {"myField": "foo2"}]} - - -class Foo4(TypedDict): - foo: Union[Bar4, Baz4] - - -class Bar4(TypedDict): - foo_bar: Annotated[str, PropertyInfo(alias="fooBar")] - - -class Baz4(TypedDict): - foo_baz: Annotated[str, PropertyInfo(alias="fooBaz")] - - -@parametrize -@pytest.mark.asyncio -async def test_union_of_typeddict(use_async: bool) -> None: - assert await transform({"foo": {"foo_bar": "bar"}}, Foo4, use_async) == {"foo": {"fooBar": "bar"}} - assert await transform({"foo": {"foo_baz": "baz"}}, Foo4, use_async) == {"foo": {"fooBaz": "baz"}} - assert await transform({"foo": {"foo_baz": "baz", "foo_bar": "bar"}}, Foo4, use_async) == { - "foo": {"fooBaz": "baz", "fooBar": "bar"} - } - - -class Foo5(TypedDict): - foo: Annotated[Union[Bar4, List[Baz4]], PropertyInfo(alias="FOO")] - - -class Bar5(TypedDict): - foo_bar: Annotated[str, PropertyInfo(alias="fooBar")] - - -class Baz5(TypedDict): - foo_baz: Annotated[str, PropertyInfo(alias="fooBaz")] - - -@parametrize -@pytest.mark.asyncio -async def test_union_of_list(use_async: bool) -> None: - assert await transform({"foo": {"foo_bar": "bar"}}, Foo5, use_async) == {"FOO": {"fooBar": "bar"}} - assert await transform( - { - "foo": [ - {"foo_baz": "baz"}, - {"foo_baz": "baz"}, - ] - }, - Foo5, - use_async, - ) == {"FOO": [{"fooBaz": "baz"}, {"fooBaz": "baz"}]} - - -class Foo6(TypedDict): - bar: Annotated[str, PropertyInfo(alias="Bar")] - - -@parametrize -@pytest.mark.asyncio -async def test_includes_unknown_keys(use_async: bool) -> None: - assert await transform({"bar": "bar", "baz_": {"FOO": 1}}, Foo6, use_async) == { - "Bar": "bar", - "baz_": {"FOO": 1}, - } - - -class Foo7(TypedDict): - bar: Annotated[List[Bar7], PropertyInfo(alias="bAr")] - foo: Bar7 - - -class Bar7(TypedDict): - foo: str - - -@parametrize -@pytest.mark.asyncio -async def test_ignores_invalid_input(use_async: bool) -> None: - assert await transform({"bar": ""}, Foo7, use_async) == {"bAr": ""} - assert await transform({"foo": ""}, Foo7, use_async) == {"foo": ""} - - -class DatetimeDict(TypedDict, total=False): - foo: Annotated[datetime, PropertyInfo(format="iso8601")] - - bar: Annotated[Optional[datetime], PropertyInfo(format="iso8601")] - - required: Required[Annotated[Optional[datetime], PropertyInfo(format="iso8601")]] - - list_: Required[Annotated[Optional[List[datetime]], PropertyInfo(format="iso8601")]] - - union: Annotated[Union[int, datetime], PropertyInfo(format="iso8601")] - - -class DateDict(TypedDict, total=False): - foo: Annotated[date, PropertyInfo(format="iso8601")] - - -class DatetimeModel(BaseModel): - foo: datetime - - -class DateModel(BaseModel): - foo: Optional[date] - - -@parametrize -@pytest.mark.asyncio -async def test_iso8601_format(use_async: bool) -> None: - dt = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") - assert await transform({"foo": dt}, DatetimeDict, use_async) == {"foo": "2023-02-23T14:16:36.337Z"} # type: ignore[comparison-overlap] - assert await transform(DatetimeModel(foo=dt), Any, use_async) == {"foo": "2023-02-23T14:16:36.337692Z"} # type: ignore[comparison-overlap] - - dt = dt.replace(tzinfo=None) - assert await transform({"foo": dt}, DatetimeDict, use_async) == {"foo": "2023-02-23T14:16:36.337"} # type: ignore[comparison-overlap] - assert await transform(DatetimeModel(foo=dt), Any, use_async) == {"foo": "2023-02-23T14:16:36.337692"} # type: ignore[comparison-overlap] - - assert await transform({"foo": None}, DateDict, use_async) == {"foo": None} # type: ignore[comparison-overlap] - assert await transform(DateModel(foo=None), Any, use_async) == {"foo": None} # type: ignore - assert await transform({"foo": date.fromisoformat("2023-02-23")}, DateDict, use_async) == {"foo": "2023-02-23"} # type: ignore[comparison-overlap] - assert await transform(DateModel(foo=date.fromisoformat("2023-02-23")), DateDict, use_async) == { - "foo": "2023-02-23" - } # type: ignore[comparison-overlap] - - -@parametrize -@pytest.mark.asyncio -async def test_optional_iso8601_format(use_async: bool) -> None: - dt = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") - assert await transform({"bar": dt}, DatetimeDict, use_async) == {"bar": "2023-02-23T14:16:36.337Z"} # type: ignore[comparison-overlap] - - assert await transform({"bar": None}, DatetimeDict, use_async) == {"bar": None} - - -@parametrize -@pytest.mark.asyncio -async def test_required_iso8601_format(use_async: bool) -> None: - dt = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") - assert await transform({"required": dt}, DatetimeDict, use_async) == { - "required": "2023-02-23T14:16:36.337Z" - } # type: ignore[comparison-overlap] - - assert await transform({"required": None}, DatetimeDict, use_async) == {"required": None} - - -@parametrize -@pytest.mark.asyncio -async def test_union_datetime(use_async: bool) -> None: - dt = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") - assert await transform({"union": dt}, DatetimeDict, use_async) == { # type: ignore[comparison-overlap] - "union": "2023-02-23T14:16:36.337Z" - } - - assert await transform({"union": "foo"}, DatetimeDict, use_async) == {"union": "foo"} - - -@parametrize -@pytest.mark.asyncio -async def test_nested_list_iso6801_format(use_async: bool) -> None: - dt1 = datetime.fromisoformat("2023-02-23T14:16:36.337692+00:00") - dt2 = parse_datetime("2022-01-15T06:34:23Z") - assert await transform({"list_": [dt1, dt2]}, DatetimeDict, use_async) == { # type: ignore[comparison-overlap] - "list_": ["2023-02-23T14:16:36.337Z", "2022-01-15T06:34:23.000Z"] - } - - -@parametrize -@pytest.mark.asyncio -async def test_datetime_custom_format(use_async: bool) -> None: - dt = parse_datetime("2022-01-15T06:34:23Z") - - result = await transform(dt, Annotated[datetime, PropertyInfo(format="custom", format_template="%H")], use_async) - assert result == "06" # type: ignore[comparison-overlap] - - -class DateDictWithRequiredAlias(TypedDict, total=False): - required_prop: Required[Annotated[date, PropertyInfo(format="iso8601", alias="prop")]] - - -@parametrize -@pytest.mark.asyncio -async def test_datetime_with_alias(use_async: bool) -> None: - assert await transform({"required_prop": None}, DateDictWithRequiredAlias, use_async) == {"prop": None} # type: ignore[comparison-overlap] - assert await transform( - {"required_prop": date.fromisoformat("2023-02-23")}, DateDictWithRequiredAlias, use_async - ) == {"prop": "2023-02-23"} # type: ignore[comparison-overlap] - - -class MyModel(BaseModel): - foo: str - - -@parametrize -@pytest.mark.asyncio -async def test_pydantic_model_to_dictionary(use_async: bool) -> None: - assert cast(Any, await transform(MyModel(foo="hi!"), Any, use_async)) == {"foo": "hi!"} - assert cast(Any, await transform(MyModel.construct(foo="hi!"), Any, use_async)) == {"foo": "hi!"} - - -@parametrize -@pytest.mark.asyncio -async def test_pydantic_empty_model(use_async: bool) -> None: - assert cast(Any, await transform(MyModel.construct(), Any, use_async)) == {} - - -@parametrize -@pytest.mark.asyncio -async def test_pydantic_unknown_field(use_async: bool) -> None: - assert cast(Any, await transform(MyModel.construct(my_untyped_field=True), Any, use_async)) == { - "my_untyped_field": True - } - - -@parametrize -@pytest.mark.asyncio -async def test_pydantic_mismatched_types(use_async: bool) -> None: - model = MyModel.construct(foo=True) - if PYDANTIC_V1: - params = await transform(model, Any, use_async) - else: - with pytest.warns(UserWarning): - params = await transform(model, Any, use_async) - assert cast(Any, params) == {"foo": True} - - -@parametrize -@pytest.mark.asyncio -async def test_pydantic_mismatched_object_type(use_async: bool) -> None: - model = MyModel.construct(foo=MyModel.construct(hello="world")) - if PYDANTIC_V1: - params = await transform(model, Any, use_async) - else: - with pytest.warns(UserWarning): - params = await transform(model, Any, use_async) - assert cast(Any, params) == {"foo": {"hello": "world"}} - - -class ModelNestedObjects(BaseModel): - nested: MyModel - - -@parametrize -@pytest.mark.asyncio -async def test_pydantic_nested_objects(use_async: bool) -> None: - model = ModelNestedObjects.construct(nested={"foo": "stainless"}) - assert isinstance(model.nested, MyModel) - assert cast(Any, await transform(model, Any, use_async)) == {"nested": {"foo": "stainless"}} - - -class ModelWithDefaultField(BaseModel): - foo: str - with_none_default: Union[str, None] = None - with_str_default: str = "foo" - - -@parametrize -@pytest.mark.asyncio -async def test_pydantic_default_field(use_async: bool) -> None: - # should be excluded when defaults are used - model = ModelWithDefaultField.construct() - assert model.with_none_default is None - assert model.with_str_default == "foo" - assert cast(Any, await transform(model, Any, use_async)) == {} - - # should be included when the default value is explicitly given - model = ModelWithDefaultField.construct(with_none_default=None, with_str_default="foo") - assert model.with_none_default is None - assert model.with_str_default == "foo" - assert cast(Any, await transform(model, Any, use_async)) == {"with_none_default": None, "with_str_default": "foo"} - - # should be included when a non-default value is explicitly given - model = ModelWithDefaultField.construct(with_none_default="bar", with_str_default="baz") - assert model.with_none_default == "bar" - assert model.with_str_default == "baz" - assert cast(Any, await transform(model, Any, use_async)) == {"with_none_default": "bar", "with_str_default": "baz"} - - -class TypedDictIterableUnion(TypedDict): - foo: Annotated[Union[Bar8, Iterable[Baz8]], PropertyInfo(alias="FOO")] - - -class Bar8(TypedDict): - foo_bar: Annotated[str, PropertyInfo(alias="fooBar")] - - -class Baz8(TypedDict): - foo_baz: Annotated[str, PropertyInfo(alias="fooBaz")] - - -@parametrize -@pytest.mark.asyncio -async def test_iterable_of_dictionaries(use_async: bool) -> None: - assert await transform({"foo": [{"foo_baz": "bar"}]}, TypedDictIterableUnion, use_async) == { - "FOO": [{"fooBaz": "bar"}] - } - assert cast(Any, await transform({"foo": ({"foo_baz": "bar"},)}, TypedDictIterableUnion, use_async)) == { - "FOO": [{"fooBaz": "bar"}] - } - - def my_iter() -> Iterable[Baz8]: - yield {"foo_baz": "hello"} - yield {"foo_baz": "world"} - - assert await transform({"foo": my_iter()}, TypedDictIterableUnion, use_async) == { - "FOO": [{"fooBaz": "hello"}, {"fooBaz": "world"}] - } - - -@parametrize -@pytest.mark.asyncio -async def test_dictionary_items(use_async: bool) -> None: - class DictItems(TypedDict): - foo_baz: Annotated[str, PropertyInfo(alias="fooBaz")] - - assert await transform({"foo": {"foo_baz": "bar"}}, Dict[str, DictItems], use_async) == {"foo": {"fooBaz": "bar"}} - - -class TypedDictIterableUnionStr(TypedDict): - foo: Annotated[Union[str, Iterable[Baz8]], PropertyInfo(alias="FOO")] - - -@parametrize -@pytest.mark.asyncio -async def test_iterable_union_str(use_async: bool) -> None: - assert await transform({"foo": "bar"}, TypedDictIterableUnionStr, use_async) == {"FOO": "bar"} - assert cast(Any, await transform(iter([{"foo_baz": "bar"}]), Union[str, Iterable[Baz8]], use_async)) == [ - {"fooBaz": "bar"} - ] - - -class TypedDictBase64Input(TypedDict): - foo: Annotated[Union[str, Base64FileInput], PropertyInfo(format="base64")] - - -@parametrize -@pytest.mark.asyncio -async def test_base64_file_input(use_async: bool) -> None: - # strings are left as-is - assert await transform({"foo": "bar"}, TypedDictBase64Input, use_async) == {"foo": "bar"} - - # pathlib.Path is automatically converted to base64 - assert await transform({"foo": SAMPLE_FILE_PATH}, TypedDictBase64Input, use_async) == { - "foo": "SGVsbG8sIHdvcmxkIQo=" - } # type: ignore[comparison-overlap] - - # io instances are automatically converted to base64 - assert await transform({"foo": io.StringIO("Hello, world!")}, TypedDictBase64Input, use_async) == { - "foo": "SGVsbG8sIHdvcmxkIQ==" - } # type: ignore[comparison-overlap] - assert await transform({"foo": io.BytesIO(b"Hello, world!")}, TypedDictBase64Input, use_async) == { - "foo": "SGVsbG8sIHdvcmxkIQ==" - } # type: ignore[comparison-overlap] - - -@parametrize -@pytest.mark.asyncio -async def test_transform_skipping(use_async: bool) -> None: - # lists of ints are left as-is - data = [1, 2, 3] - assert await transform(data, List[int], use_async) is data - - # iterables of ints are converted to a list - data = iter([1, 2, 3]) - assert await transform(data, Iterable[int], use_async) == [1, 2, 3] - - -@parametrize -@pytest.mark.asyncio -async def test_strips_notgiven(use_async: bool) -> None: - assert await transform({"foo_bar": "bar"}, Foo1, use_async) == {"fooBar": "bar"} - assert await transform({"foo_bar": not_given}, Foo1, use_async) == {} - - -@parametrize -@pytest.mark.asyncio -async def test_strips_omit(use_async: bool) -> None: - assert await transform({"foo_bar": "bar"}, Foo1, use_async) == {"fooBar": "bar"} - assert await transform({"foo_bar": omit}, Foo1, use_async) == {} diff --git a/tests/test_utils/test_datetime_parse.py b/tests/test_utils/test_datetime_parse.py deleted file mode 100644 index 7d4e3999f..000000000 --- a/tests/test_utils/test_datetime_parse.py +++ /dev/null @@ -1,110 +0,0 @@ -""" -Copied from https://github.com/pydantic/pydantic/blob/v1.10.22/tests/test_datetime_parse.py -with modifications so it works without pydantic v1 imports. -""" - -from typing import Type, Union -from datetime import date, datetime, timezone, timedelta - -import pytest - -from metronome._utils import parse_date, parse_datetime - - -def create_tz(minutes: int) -> timezone: - return timezone(timedelta(minutes=minutes)) - - -@pytest.mark.parametrize( - "value,result", - [ - # Valid inputs - ("1494012444.883309", date(2017, 5, 5)), - (b"1494012444.883309", date(2017, 5, 5)), - (1_494_012_444.883_309, date(2017, 5, 5)), - ("1494012444", date(2017, 5, 5)), - (1_494_012_444, date(2017, 5, 5)), - (0, date(1970, 1, 1)), - ("2012-04-23", date(2012, 4, 23)), - (b"2012-04-23", date(2012, 4, 23)), - ("2012-4-9", date(2012, 4, 9)), - (date(2012, 4, 9), date(2012, 4, 9)), - (datetime(2012, 4, 9, 12, 15), date(2012, 4, 9)), - # Invalid inputs - ("x20120423", ValueError), - ("2012-04-56", ValueError), - (19_999_999_999, date(2603, 10, 11)), # just before watershed - (20_000_000_001, date(1970, 8, 20)), # just after watershed - (1_549_316_052, date(2019, 2, 4)), # nowish in s - (1_549_316_052_104, date(2019, 2, 4)), # nowish in ms - (1_549_316_052_104_324, date(2019, 2, 4)), # nowish in μs - (1_549_316_052_104_324_096, date(2019, 2, 4)), # nowish in ns - ("infinity", date(9999, 12, 31)), - ("inf", date(9999, 12, 31)), - (float("inf"), date(9999, 12, 31)), - ("infinity ", date(9999, 12, 31)), - (int("1" + "0" * 100), date(9999, 12, 31)), - (1e1000, date(9999, 12, 31)), - ("-infinity", date(1, 1, 1)), - ("-inf", date(1, 1, 1)), - ("nan", ValueError), - ], -) -def test_date_parsing(value: Union[str, bytes, int, float], result: Union[date, Type[Exception]]) -> None: - if type(result) == type and issubclass(result, Exception): # pyright: ignore[reportUnnecessaryIsInstance] - with pytest.raises(result): - parse_date(value) - else: - assert parse_date(value) == result - - -@pytest.mark.parametrize( - "value,result", - [ - # Valid inputs - # values in seconds - ("1494012444.883309", datetime(2017, 5, 5, 19, 27, 24, 883_309, tzinfo=timezone.utc)), - (1_494_012_444.883_309, datetime(2017, 5, 5, 19, 27, 24, 883_309, tzinfo=timezone.utc)), - ("1494012444", datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)), - (b"1494012444", datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)), - (1_494_012_444, datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)), - # values in ms - ("1494012444000.883309", datetime(2017, 5, 5, 19, 27, 24, 883, tzinfo=timezone.utc)), - ("-1494012444000.883309", datetime(1922, 8, 29, 4, 32, 35, 999117, tzinfo=timezone.utc)), - (1_494_012_444_000, datetime(2017, 5, 5, 19, 27, 24, tzinfo=timezone.utc)), - ("2012-04-23T09:15:00", datetime(2012, 4, 23, 9, 15)), - ("2012-4-9 4:8:16", datetime(2012, 4, 9, 4, 8, 16)), - ("2012-04-23T09:15:00Z", datetime(2012, 4, 23, 9, 15, 0, 0, timezone.utc)), - ("2012-4-9 4:8:16-0320", datetime(2012, 4, 9, 4, 8, 16, 0, create_tz(-200))), - ("2012-04-23T10:20:30.400+02:30", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(150))), - ("2012-04-23T10:20:30.400+02", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(120))), - ("2012-04-23T10:20:30.400-02", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(-120))), - (b"2012-04-23T10:20:30.400-02", datetime(2012, 4, 23, 10, 20, 30, 400_000, create_tz(-120))), - (datetime(2017, 5, 5), datetime(2017, 5, 5)), - (0, datetime(1970, 1, 1, 0, 0, 0, tzinfo=timezone.utc)), - # Invalid inputs - ("x20120423091500", ValueError), - ("2012-04-56T09:15:90", ValueError), - ("2012-04-23T11:05:00-25:00", ValueError), - (19_999_999_999, datetime(2603, 10, 11, 11, 33, 19, tzinfo=timezone.utc)), # just before watershed - (20_000_000_001, datetime(1970, 8, 20, 11, 33, 20, 1000, tzinfo=timezone.utc)), # just after watershed - (1_549_316_052, datetime(2019, 2, 4, 21, 34, 12, 0, tzinfo=timezone.utc)), # nowish in s - (1_549_316_052_104, datetime(2019, 2, 4, 21, 34, 12, 104_000, tzinfo=timezone.utc)), # nowish in ms - (1_549_316_052_104_324, datetime(2019, 2, 4, 21, 34, 12, 104_324, tzinfo=timezone.utc)), # nowish in μs - (1_549_316_052_104_324_096, datetime(2019, 2, 4, 21, 34, 12, 104_324, tzinfo=timezone.utc)), # nowish in ns - ("infinity", datetime(9999, 12, 31, 23, 59, 59, 999999)), - ("inf", datetime(9999, 12, 31, 23, 59, 59, 999999)), - ("inf ", datetime(9999, 12, 31, 23, 59, 59, 999999)), - (1e50, datetime(9999, 12, 31, 23, 59, 59, 999999)), - (float("inf"), datetime(9999, 12, 31, 23, 59, 59, 999999)), - ("-infinity", datetime(1, 1, 1, 0, 0)), - ("-inf", datetime(1, 1, 1, 0, 0)), - ("nan", ValueError), - ], -) -def test_datetime_parsing(value: Union[str, bytes, int, float], result: Union[datetime, Type[Exception]]) -> None: - if type(result) == type and issubclass(result, Exception): # pyright: ignore[reportUnnecessaryIsInstance] - with pytest.raises(result): - parse_datetime(value) - else: - assert parse_datetime(value) == result diff --git a/tests/test_utils/test_json.py b/tests/test_utils/test_json.py deleted file mode 100644 index 785aed7fe..000000000 --- a/tests/test_utils/test_json.py +++ /dev/null @@ -1,126 +0,0 @@ -from __future__ import annotations - -import datetime -from typing import Union - -import pydantic - -from metronome import _compat -from metronome._utils._json import openapi_dumps - - -class TestOpenapiDumps: - def test_basic(self) -> None: - data = {"key": "value", "number": 42} - json_bytes = openapi_dumps(data) - assert json_bytes == b'{"key":"value","number":42}' - - def test_datetime_serialization(self) -> None: - dt = datetime.datetime(2023, 1, 1, 12, 0, 0) - data = {"datetime": dt} - json_bytes = openapi_dumps(data) - assert json_bytes == b'{"datetime":"2023-01-01T12:00:00"}' - - def test_pydantic_model_serialization(self) -> None: - class User(pydantic.BaseModel): - first_name: str - last_name: str - age: int - - model_instance = User(first_name="John", last_name="Kramer", age=83) - data = {"model": model_instance} - json_bytes = openapi_dumps(data) - assert json_bytes == b'{"model":{"first_name":"John","last_name":"Kramer","age":83}}' - - def test_pydantic_model_with_default_values(self) -> None: - class User(pydantic.BaseModel): - name: str - role: str = "user" - active: bool = True - score: int = 0 - - model_instance = User(name="Alice") - data = {"model": model_instance} - json_bytes = openapi_dumps(data) - assert json_bytes == b'{"model":{"name":"Alice"}}' - - def test_pydantic_model_with_default_values_overridden(self) -> None: - class User(pydantic.BaseModel): - name: str - role: str = "user" - active: bool = True - - model_instance = User(name="Bob", role="admin", active=False) - data = {"model": model_instance} - json_bytes = openapi_dumps(data) - assert json_bytes == b'{"model":{"name":"Bob","role":"admin","active":false}}' - - def test_pydantic_model_with_alias(self) -> None: - class User(pydantic.BaseModel): - first_name: str = pydantic.Field(alias="firstName") - last_name: str = pydantic.Field(alias="lastName") - - model_instance = User(firstName="John", lastName="Doe") - data = {"model": model_instance} - json_bytes = openapi_dumps(data) - assert json_bytes == b'{"model":{"firstName":"John","lastName":"Doe"}}' - - def test_pydantic_model_with_alias_and_default(self) -> None: - class User(pydantic.BaseModel): - user_name: str = pydantic.Field(alias="userName") - user_role: str = pydantic.Field(default="member", alias="userRole") - is_active: bool = pydantic.Field(default=True, alias="isActive") - - model_instance = User(userName="charlie") - data = {"model": model_instance} - json_bytes = openapi_dumps(data) - assert json_bytes == b'{"model":{"userName":"charlie"}}' - - model_with_overrides = User(userName="diana", userRole="admin", isActive=False) - data = {"model": model_with_overrides} - json_bytes = openapi_dumps(data) - assert json_bytes == b'{"model":{"userName":"diana","userRole":"admin","isActive":false}}' - - def test_pydantic_model_with_nested_models_and_defaults(self) -> None: - class Address(pydantic.BaseModel): - street: str - city: str = "Unknown" - - class User(pydantic.BaseModel): - name: str - address: Address - verified: bool = False - - if _compat.PYDANTIC_V1: - # to handle forward references in Pydantic v1 - User.update_forward_refs(**locals()) # type: ignore[reportDeprecated] - - address = Address(street="123 Main St") - user = User(name="Diana", address=address) - data = {"user": user} - json_bytes = openapi_dumps(data) - assert json_bytes == b'{"user":{"name":"Diana","address":{"street":"123 Main St"}}}' - - address_with_city = Address(street="456 Oak Ave", city="Boston") - user_verified = User(name="Eve", address=address_with_city, verified=True) - data = {"user": user_verified} - json_bytes = openapi_dumps(data) - assert ( - json_bytes == b'{"user":{"name":"Eve","address":{"street":"456 Oak Ave","city":"Boston"},"verified":true}}' - ) - - def test_pydantic_model_with_optional_fields(self) -> None: - class User(pydantic.BaseModel): - name: str - email: Union[str, None] - phone: Union[str, None] - - model_with_none = User(name="Eve", email=None, phone=None) - data = {"model": model_with_none} - json_bytes = openapi_dumps(data) - assert json_bytes == b'{"model":{"name":"Eve","email":null,"phone":null}}' - - model_with_values = User(name="Frank", email="frank@example.com", phone=None) - data = {"model": model_with_values} - json_bytes = openapi_dumps(data) - assert json_bytes == b'{"model":{"name":"Frank","email":"frank@example.com","phone":null}}' diff --git a/tests/test_utils/test_proxy.py b/tests/test_utils/test_proxy.py deleted file mode 100644 index 8f3cd8a0c..000000000 --- a/tests/test_utils/test_proxy.py +++ /dev/null @@ -1,34 +0,0 @@ -import operator -from typing import Any -from typing_extensions import override - -from metronome._utils import LazyProxy - - -class RecursiveLazyProxy(LazyProxy[Any]): - @override - def __load__(self) -> Any: - return self - - def __call__(self, *_args: Any, **_kwds: Any) -> Any: - raise RuntimeError("This should never be called!") - - -def test_recursive_proxy() -> None: - proxy = RecursiveLazyProxy() - assert repr(proxy) == "RecursiveLazyProxy" - assert str(proxy) == "RecursiveLazyProxy" - assert dir(proxy) == [] - assert type(proxy).__name__ == "RecursiveLazyProxy" - assert type(operator.attrgetter("name.foo.bar.baz")(proxy)).__name__ == "RecursiveLazyProxy" - - -def test_isinstance_does_not_error() -> None: - class AlwaysErrorProxy(LazyProxy[Any]): - @override - def __load__(self) -> Any: - raise RuntimeError("Mocking missing dependency") - - proxy = AlwaysErrorProxy() - assert not isinstance(proxy, dict) - assert isinstance(proxy, LazyProxy) diff --git a/tests/test_utils/test_typing.py b/tests/test_utils/test_typing.py deleted file mode 100644 index b7d733d12..000000000 --- a/tests/test_utils/test_typing.py +++ /dev/null @@ -1,73 +0,0 @@ -from __future__ import annotations - -from typing import Generic, TypeVar, cast - -from metronome._utils import extract_type_var_from_base - -_T = TypeVar("_T") -_T2 = TypeVar("_T2") -_T3 = TypeVar("_T3") - - -class BaseGeneric(Generic[_T]): ... - - -class SubclassGeneric(BaseGeneric[_T]): ... - - -class BaseGenericMultipleTypeArgs(Generic[_T, _T2, _T3]): ... - - -class SubclassGenericMultipleTypeArgs(BaseGenericMultipleTypeArgs[_T, _T2, _T3]): ... - - -class SubclassDifferentOrderGenericMultipleTypeArgs(BaseGenericMultipleTypeArgs[_T2, _T, _T3]): ... - - -def test_extract_type_var() -> None: - assert ( - extract_type_var_from_base( - BaseGeneric[int], - index=0, - generic_bases=cast("tuple[type, ...]", (BaseGeneric,)), - ) - == int - ) - - -def test_extract_type_var_generic_subclass() -> None: - assert ( - extract_type_var_from_base( - SubclassGeneric[int], - index=0, - generic_bases=cast("tuple[type, ...]", (BaseGeneric,)), - ) - == int - ) - - -def test_extract_type_var_multiple() -> None: - typ = BaseGenericMultipleTypeArgs[int, str, None] - - generic_bases = cast("tuple[type, ...]", (BaseGenericMultipleTypeArgs,)) - assert extract_type_var_from_base(typ, index=0, generic_bases=generic_bases) == int - assert extract_type_var_from_base(typ, index=1, generic_bases=generic_bases) == str - assert extract_type_var_from_base(typ, index=2, generic_bases=generic_bases) == type(None) - - -def test_extract_type_var_generic_subclass_multiple() -> None: - typ = SubclassGenericMultipleTypeArgs[int, str, None] - - generic_bases = cast("tuple[type, ...]", (BaseGenericMultipleTypeArgs,)) - assert extract_type_var_from_base(typ, index=0, generic_bases=generic_bases) == int - assert extract_type_var_from_base(typ, index=1, generic_bases=generic_bases) == str - assert extract_type_var_from_base(typ, index=2, generic_bases=generic_bases) == type(None) - - -def test_extract_type_var_generic_subclass_different_ordering_multiple() -> None: - typ = SubclassDifferentOrderGenericMultipleTypeArgs[int, str, None] - - generic_bases = cast("tuple[type, ...]", (BaseGenericMultipleTypeArgs,)) - assert extract_type_var_from_base(typ, index=0, generic_bases=generic_bases) == int - assert extract_type_var_from_base(typ, index=1, generic_bases=generic_bases) == str - assert extract_type_var_from_base(typ, index=2, generic_bases=generic_bases) == type(None) diff --git a/tests/utils.py b/tests/utils.py deleted file mode 100644 index 717b4a2c0..000000000 --- a/tests/utils.py +++ /dev/null @@ -1,167 +0,0 @@ -from __future__ import annotations - -import os -import inspect -import traceback -import contextlib -from typing import Any, TypeVar, Iterator, Sequence, cast -from datetime import date, datetime -from typing_extensions import Literal, get_args, get_origin, assert_type - -from metronome._types import Omit, NoneType -from metronome._utils import ( - is_dict, - is_list, - is_list_type, - is_union_type, - extract_type_arg, - is_sequence_type, - is_annotated_type, - is_type_alias_type, -) -from metronome._compat import PYDANTIC_V1, field_outer_type, get_model_fields -from metronome._models import BaseModel - -BaseModelT = TypeVar("BaseModelT", bound=BaseModel) - - -def assert_matches_model(model: type[BaseModelT], value: BaseModelT, *, path: list[str]) -> bool: - for name, field in get_model_fields(model).items(): - field_value = getattr(value, name) - if PYDANTIC_V1: - # in v1 nullability was structured differently - # https://docs.pydantic.dev/2.0/migration/#required-optional-and-nullable-fields - allow_none = getattr(field, "allow_none", False) - else: - allow_none = False - - assert_matches_type( - field_outer_type(field), - field_value, - path=[*path, name], - allow_none=allow_none, - ) - - return True - - -# Note: the `path` argument is only used to improve error messages when `--showlocals` is used -def assert_matches_type( - type_: Any, - value: object, - *, - path: list[str], - allow_none: bool = False, -) -> None: - if is_type_alias_type(type_): - type_ = type_.__value__ - - # unwrap `Annotated[T, ...]` -> `T` - if is_annotated_type(type_): - type_ = extract_type_arg(type_, 0) - - if allow_none and value is None: - return - - if type_ is None or type_ is NoneType: - assert value is None - return - - origin = get_origin(type_) or type_ - - if is_list_type(type_): - return _assert_list_type(type_, value) - - if is_sequence_type(type_): - assert isinstance(value, Sequence) - inner_type = get_args(type_)[0] - for entry in value: # type: ignore - assert_type(inner_type, entry) # type: ignore - return - - if origin == str: - assert isinstance(value, str) - elif origin == int: - assert isinstance(value, int) - elif origin == bool: - assert isinstance(value, bool) - elif origin == float: - assert isinstance(value, float) - elif origin == bytes: - assert isinstance(value, bytes) - elif origin == datetime: - assert isinstance(value, datetime) - elif origin == date: - assert isinstance(value, date) - elif origin == object: - # nothing to do here, the expected type is unknown - pass - elif origin == Literal: - assert value in get_args(type_) - elif origin == dict: - assert is_dict(value) - - args = get_args(type_) - key_type = args[0] - items_type = args[1] - - for key, item in value.items(): - assert_matches_type(key_type, key, path=[*path, ""]) - assert_matches_type(items_type, item, path=[*path, ""]) - elif is_union_type(type_): - variants = get_args(type_) - - try: - none_index = variants.index(type(None)) - except ValueError: - pass - else: - # special case Optional[T] for better error messages - if len(variants) == 2: - if value is None: - # valid - return - - return assert_matches_type(type_=variants[not none_index], value=value, path=path) - - for i, variant in enumerate(variants): - try: - assert_matches_type(variant, value, path=[*path, f"variant {i}"]) - return - except AssertionError: - traceback.print_exc() - continue - - raise AssertionError("Did not match any variants") - elif issubclass(origin, BaseModel): - assert isinstance(value, type_) - assert assert_matches_model(type_, cast(Any, value), path=path) - elif inspect.isclass(origin) and origin.__name__ == "HttpxBinaryResponseContent": - assert value.__class__.__name__ == "HttpxBinaryResponseContent" - else: - assert None, f"Unhandled field type: {type_}" - - -def _assert_list_type(type_: type[object], value: object) -> None: - assert is_list(value) - - inner_type = get_args(type_)[0] - for entry in value: - assert_type(inner_type, entry) # type: ignore - - -@contextlib.contextmanager -def update_env(**new_env: str | Omit) -> Iterator[None]: - old = os.environ.copy() - - try: - for name, value in new_env.items(): - if isinstance(value, Omit): - os.environ.pop(name, None) - else: - os.environ[name] = value - - yield None - finally: - os.environ.clear() - os.environ.update(old) From fd0e751e91d49d5a11c2fc100d6933276439f851 Mon Sep 17 00:00:00 2001 From: mahamed eltorky <236695151+samarsamer251-glitch@users.noreply.github.com> Date: Fri, 27 Mar 2026 00:40:17 +0200 Subject: [PATCH 08/17] Delete .github/workflows directory --- .github/workflows/ci.yml | 102 --------------------------- .github/workflows/publish-pypi.yml | 31 -------- .github/workflows/release-doctor.yml | 21 ------ 3 files changed, 154 deletions(-) delete mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/publish-pypi.yml delete mode 100644 .github/workflows/release-doctor.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 78dd54b48..000000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,102 +0,0 @@ -name: CI -on: - push: - branches-ignore: - - 'generated' - - 'codegen/**' - - 'integrated/**' - - 'stl-preview-head/**' - - 'stl-preview-base/**' - pull_request: - branches-ignore: - - 'stl-preview-head/**' - - 'stl-preview-base/**' - -jobs: - lint: - timeout-minutes: 10 - name: lint - runs-on: ${{ github.repository == 'stainless-sdks/metronome-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} - if: github.event_name == 'push' || github.event.pull_request.head.repo.fork - steps: - - uses: actions/checkout@v6 - - - name: Install Rye - run: | - curl -sSf https://rye.astral.sh/get | bash - echo "$HOME/.rye/shims" >> $GITHUB_PATH - env: - RYE_VERSION: '0.44.0' - RYE_INSTALL_OPTION: '--yes' - - - name: Install dependencies - run: rye sync --all-features - - - name: Run lints - run: ./scripts/lint - - build: - if: github.event_name == 'push' || github.event.pull_request.head.repo.fork - timeout-minutes: 10 - name: build - permissions: - contents: read - id-token: write - runs-on: ${{ github.repository == 'stainless-sdks/metronome-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} - steps: - - uses: actions/checkout@v6 - - - name: Install Rye - run: | - curl -sSf https://rye.astral.sh/get | bash - echo "$HOME/.rye/shims" >> $GITHUB_PATH - env: - RYE_VERSION: '0.44.0' - RYE_INSTALL_OPTION: '--yes' - - - name: Install dependencies - run: rye sync --all-features - - - name: Run build - run: rye build - - - name: Get GitHub OIDC Token - if: |- - github.repository == 'stainless-sdks/metronome-python' && - !startsWith(github.ref, 'refs/heads/stl/') - id: github-oidc - uses: actions/github-script@v8 - with: - script: core.setOutput('github_token', await core.getIDToken()); - - - name: Upload tarball - if: |- - github.repository == 'stainless-sdks/metronome-python' && - !startsWith(github.ref, 'refs/heads/stl/') - env: - URL: https://pkg.stainless.com/s - AUTH: ${{ steps.github-oidc.outputs.github_token }} - SHA: ${{ github.sha }} - run: ./scripts/utils/upload-artifact.sh - - test: - timeout-minutes: 10 - name: test - runs-on: ${{ github.repository == 'stainless-sdks/metronome-python' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} - if: github.event_name == 'push' || github.event.pull_request.head.repo.fork - steps: - - uses: actions/checkout@v6 - - - name: Install Rye - run: | - curl -sSf https://rye.astral.sh/get | bash - echo "$HOME/.rye/shims" >> $GITHUB_PATH - env: - RYE_VERSION: '0.44.0' - RYE_INSTALL_OPTION: '--yes' - - - name: Bootstrap - run: ./scripts/bootstrap - - - name: Run tests - run: ./scripts/test diff --git a/.github/workflows/publish-pypi.yml b/.github/workflows/publish-pypi.yml deleted file mode 100644 index a7d55b51b..000000000 --- a/.github/workflows/publish-pypi.yml +++ /dev/null @@ -1,31 +0,0 @@ -# This workflow is triggered when a GitHub release is created. -# It can also be run manually to re-publish to PyPI in case it failed for some reason. -# You can run this workflow by navigating to https://www.github.com/Metronome-Industries/metronome-python/actions/workflows/publish-pypi.yml -name: Publish PyPI -on: - workflow_dispatch: - - release: - types: [published] - -jobs: - publish: - name: publish - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v6 - - - name: Install Rye - run: | - curl -sSf https://rye.astral.sh/get | bash - echo "$HOME/.rye/shims" >> $GITHUB_PATH - env: - RYE_VERSION: '0.44.0' - RYE_INSTALL_OPTION: '--yes' - - - name: Publish to PyPI - run: | - bash ./bin/publish-pypi - env: - PYPI_TOKEN: ${{ secrets.METRONOME_PYPI_TOKEN || secrets.PYPI_TOKEN }} diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml deleted file mode 100644 index a95370196..000000000 --- a/.github/workflows/release-doctor.yml +++ /dev/null @@ -1,21 +0,0 @@ -name: Release Doctor -on: - pull_request: - branches: - - main - workflow_dispatch: - -jobs: - release_doctor: - name: release doctor - runs-on: ubuntu-latest - if: github.repository == 'Metronome-Industries/metronome-python' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') - - steps: - - uses: actions/checkout@v6 - - - name: Check release environment - run: | - bash ./bin/check-release-environment - env: - PYPI_TOKEN: ${{ secrets.METRONOME_PYPI_TOKEN || secrets.PYPI_TOKEN }} From f602555006ffd1941255f345f74235c6a73ba2ab Mon Sep 17 00:00:00 2001 From: mahamed eltorky <236695151+samarsamer251-glitch@users.noreply.github.com> Date: Fri, 27 Mar 2026 00:40:39 +0200 Subject: [PATCH 09/17] Delete src/metronome directory --- src/metronome/__init__.py | 102 - src/metronome/_base_client.py | 2127 ------------ src/metronome/_client.py | 508 --- src/metronome/_compat.py | 219 -- src/metronome/_constants.py | 14 - src/metronome/_exceptions.py | 108 - src/metronome/_files.py | 123 - src/metronome/_models.py | 872 ----- src/metronome/_qs.py | 150 - src/metronome/_resource.py | 43 - src/metronome/_response.py | 833 ----- src/metronome/_streaming.py | 338 -- src/metronome/_types.py | 270 -- src/metronome/_utils/__init__.py | 64 - src/metronome/_utils/_compat.py | 45 - src/metronome/_utils/_datetime_parse.py | 136 - src/metronome/_utils/_json.py | 35 - src/metronome/_utils/_logs.py | 25 - src/metronome/_utils/_proxy.py | 65 - src/metronome/_utils/_reflection.py | 42 - src/metronome/_utils/_resources_proxy.py | 24 - src/metronome/_utils/_streams.py | 12 - src/metronome/_utils/_sync.py | 58 - src/metronome/_utils/_transform.py | 463 --- src/metronome/_utils/_typing.py | 156 - src/metronome/_utils/_utils.py | 421 --- src/metronome/_version.py | 4 - src/metronome/lib/.keep | 4 - src/metronome/pagination.py | 173 - src/metronome/py.typed | 0 src/metronome/resources/__init__.py | 33 - src/metronome/resources/v1/__init__.py | 243 -- src/metronome/resources/v1/alerts.py | 603 ---- src/metronome/resources/v1/audit_logs.py | 328 -- .../resources/v1/billable_metrics.py | 636 ---- .../resources/v1/contracts/__init__.py | 61 - .../resources/v1/contracts/contracts.py | 2840 ----------------- .../resources/v1/contracts/named_schedules.py | 334 -- .../resources/v1/contracts/products.py | 896 ------ .../v1/contracts/rate_cards/__init__.py | 61 - .../contracts/rate_cards/named_schedules.py | 350 -- .../v1/contracts/rate_cards/product_orders.py | 292 -- .../v1/contracts/rate_cards/rate_cards.py | 1111 ------- .../v1/contracts/rate_cards/rates.py | 562 ---- src/metronome/resources/v1/credit_grants.py | 874 ----- src/metronome/resources/v1/custom_fields.py | 911 ------ .../resources/v1/customers/__init__.py | 117 - .../resources/v1/customers/alerts.py | 670 ---- .../resources/v1/customers/billing_config.py | 547 ---- .../resources/v1/customers/commits.py | 865 ----- .../resources/v1/customers/credits.py | 779 ----- .../resources/v1/customers/customers.py | 2135 ------------- .../resources/v1/customers/invoices.py | 1088 ------- .../resources/v1/customers/named_schedules.py | 334 -- src/metronome/resources/v1/customers/plans.py | 645 ---- src/metronome/resources/v1/dashboards.py | 272 -- src/metronome/resources/v1/invoices.py | 298 -- src/metronome/resources/v1/packages.py | 892 ------ src/metronome/resources/v1/payments.py | 409 --- src/metronome/resources/v1/plans.py | 549 ---- src/metronome/resources/v1/pricing_units.py | 214 -- src/metronome/resources/v1/services.py | 157 - .../resources/v1/settings/__init__.py | 33 - .../v1/settings/billing_providers.py | 303 -- .../resources/v1/settings/settings.py | 279 -- src/metronome/resources/v1/usage.py | 1026 ------ src/metronome/resources/v1/v1.py | 798 ----- src/metronome/resources/v2/__init__.py | 33 - src/metronome/resources/v2/contracts.py | 1361 -------- src/metronome/resources/v2/v2.py | 102 - src/metronome/types/__init__.py | 42 - src/metronome/types/shared/__init__.py | 42 - src/metronome/types/shared/balance_filter.py | 19 - .../types/shared/base_threshold_commit.py | 23 - .../types/shared/base_usage_filter.py | 16 - src/metronome/types/shared/commit.py | 370 --- .../shared/commit_hierarchy_configuration.py | 39 - src/metronome/types/shared/commit_rate.py | 28 - .../types/shared/commit_specifier.py | 24 - .../types/shared/commit_specifier_input.py | 32 - src/metronome/types/shared/contract.py | 154 - src/metronome/types/shared/contract_v2.py | 1150 ------- .../shared/contract_without_amendments.py | 393 --- src/metronome/types/shared/credit.py | 235 -- .../types/shared/credit_type_data.py | 11 - src/metronome/types/shared/discount.py | 30 - .../types/shared/event_type_filter.py | 25 - .../types/shared/hierarchy_configuration.py | 77 - src/metronome/types/shared/id.py | 9 - src/metronome/types/shared/override.py | 96 - src/metronome/types/shared/override_tier.py | 13 - src/metronome/types/shared/overwrite_rate.py | 41 - .../types/shared/payment_gate_config.py | 61 - .../types/shared/payment_gate_config_v2.py | 61 - ...prepaid_balance_threshold_configuration.py | 63 - ...paid_balance_threshold_configuration_v2.py | 65 - src/metronome/types/shared/pro_service.py | 36 - src/metronome/types/shared/property_filter.py | 36 - src/metronome/types/shared/rate.py | 47 - .../recurring_commit_subscription_config.py | 20 - .../types/shared/schedule_duration.py | 25 - .../types/shared/schedule_point_in_time.py | 35 - .../types/shared/scheduled_charge.py | 34 - .../shared/spend_threshold_configuration.py | 27 - .../spend_threshold_configuration_v2.py | 27 - src/metronome/types/shared/subscription.py | 133 - src/metronome/types/shared/tier.py | 13 - .../shared/update_base_threshold_commit.py | 23 - src/metronome/types/shared_params/__init__.py | 22 - .../types/shared_params/balance_filter.py | 21 - .../shared_params/base_threshold_commit.py | 23 - .../types/shared_params/base_usage_filter.py | 20 - .../commit_hierarchy_configuration.py | 41 - .../types/shared_params/commit_rate.py | 29 - .../shared_params/commit_specifier_input.py | 35 - .../types/shared_params/event_type_filter.py | 27 - .../shared_params/payment_gate_config.py | 61 - .../shared_params/payment_gate_config_v2.py | 61 - ...prepaid_balance_threshold_configuration.py | 66 - ...paid_balance_threshold_configuration_v2.py | 68 - .../types/shared_params/property_filter.py | 38 - .../spend_threshold_configuration.py | 30 - .../spend_threshold_configuration_v2.py | 30 - src/metronome/types/shared_params/tier.py | 13 - .../update_base_threshold_commit.py | 23 - src/metronome/types/v1/__init__.py | 173 - .../types/v1/alert_archive_params.py | 18 - .../types/v1/alert_archive_response.py | 10 - src/metronome/types/v1/alert_create_params.py | 141 - .../types/v1/alert_create_response.py | 10 - .../types/v1/audit_log_list_params.py | 43 - .../types/v1/audit_log_list_response.py | 45 - .../v1/billable_metric_archive_params.py | 11 - .../v1/billable_metric_archive_response.py | 10 - .../types/v1/billable_metric_create_params.py | 54 - .../v1/billable_metric_create_response.py | 10 - .../types/v1/billable_metric_list_params.py | 18 - .../types/v1/billable_metric_list_response.py | 58 - .../v1/billable_metric_retrieve_response.py | 62 - ...ontract_add_manual_balance_entry_params.py | 46 - .../types/v1/contract_amend_params.py | 851 ----- .../types/v1/contract_amend_response.py | 10 - .../types/v1/contract_archive_params.py | 21 - .../types/v1/contract_archive_response.py | 10 - ...tract_create_historical_invoices_params.py | 70 - ...act_create_historical_invoices_response.py | 12 - .../types/v1/contract_create_params.py | 1464 --------- .../types/v1/contract_create_response.py | 10 - .../v1/contract_get_net_balance_params.py | 34 - .../v1/contract_get_net_balance_response.py | 23 - .../types/v1/contract_list_balances_params.py | 53 - .../v1/contract_list_balances_response.py | 11 - .../types/v1/contract_list_params.py | 45 - .../types/v1/contract_list_response.py | 12 - .../types/v1/contract_retrieve_params.py | 25 - .../contract_retrieve_rate_schedule_params.py | 67 - ...ontract_retrieve_rate_schedule_response.py | 51 - .../types/v1/contract_retrieve_response.py | 10 - ...ve_subscription_quantity_history_params.py | 15 - ..._subscription_quantity_history_response.py | 34 - ...ct_schedule_pro_services_invoice_params.py | 62 - ..._schedule_pro_services_invoice_response.py | 12 - .../v1/contract_set_usage_filter_params.py | 24 - .../v1/contract_update_end_date_params.py | 33 - .../v1/contract_update_end_date_response.py | 10 - src/metronome/types/v1/contracts/__init__.py | 38 - .../named_schedule_retrieve_params.py | 25 - .../named_schedule_retrieve_response.py | 20 - .../contracts/named_schedule_update_params.py | 29 - .../v1/contracts/product_archive_params.py | 12 - .../v1/contracts/product_archive_response.py | 10 - .../v1/contracts/product_create_params.py | 90 - .../v1/contracts/product_create_response.py | 10 - .../v1/contracts/product_list_item_state.py | 77 - .../types/v1/contracts/product_list_params.py | 18 - .../v1/contracts/product_list_response.py | 95 - .../v1/contracts/product_retrieve_params.py | 11 - .../v1/contracts/product_retrieve_response.py | 99 - .../v1/contracts/product_update_params.py | 113 - .../v1/contracts/product_update_response.py | 10 - .../types/v1/contracts/quantity_conversion.py | 24 - .../v1/contracts/quantity_conversion_param.py | 23 - .../types/v1/contracts/quantity_rounding.py | 18 - .../v1/contracts/quantity_rounding_param.py | 18 - .../v1/contracts/rate_card_archive_params.py | 11 - .../contracts/rate_card_archive_response.py | 10 - .../v1/contracts/rate_card_create_params.py | 51 - .../v1/contracts/rate_card_create_response.py | 10 - .../v1/contracts/rate_card_list_params.py | 17 - .../v1/contracts/rate_card_list_response.py | 44 - .../v1/contracts/rate_card_retrieve_params.py | 11 - ...rate_card_retrieve_rate_schedule_params.py | 60 - ...te_card_retrieve_rate_schedule_response.py | 47 - .../contracts/rate_card_retrieve_response.py | 48 - .../v1/contracts/rate_card_update_params.py | 36 - .../v1/contracts/rate_card_update_response.py | 10 - .../types/v1/contracts/rate_cards/__init__.py | 17 - .../named_schedule_retrieve_params.py | 28 - .../named_schedule_retrieve_response.py | 20 - .../named_schedule_update_params.py | 32 - .../rate_cards/product_order_set_params.py | 16 - .../rate_cards/product_order_set_response.py | 10 - .../rate_cards/product_order_update_params.py | 23 - .../product_order_update_response.py | 10 - .../rate_cards/rate_add_many_params.py | 86 - .../rate_cards/rate_add_many_response.py | 11 - .../contracts/rate_cards/rate_add_params.py | 83 - .../contracts/rate_cards/rate_add_response.py | 59 - .../contracts/rate_cards/rate_list_params.py | 61 - .../rate_cards/rate_list_response.py | 41 - .../types/v1/credit_grant_create_params.py | 112 - .../types/v1/credit_grant_create_response.py | 10 - .../types/v1/credit_grant_edit_params.py | 25 - .../types/v1/credit_grant_edit_response.py | 10 - .../v1/credit_grant_list_entries_params.py | 46 - .../v1/credit_grant_list_entries_response.py | 72 - .../types/v1/credit_grant_list_params.py | 44 - .../types/v1/credit_grant_list_response.py | 115 - .../types/v1/credit_grant_void_params.py | 17 - .../types/v1/credit_grant_void_response.py | 10 - src/metronome/types/v1/credit_ledger_entry.py | 35 - .../types/v1/custom_field_add_key_params.py | 40 - .../v1/custom_field_delete_values_params.py | 42 - .../types/v1/custom_field_list_keys_params.py | 41 - .../v1/custom_field_list_keys_response.py | 38 - .../v1/custom_field_remove_key_params.py | 38 - .../v1/custom_field_set_values_params.py | 42 - src/metronome/types/v1/customer.py | 29 - ...r_archive_billing_configurations_params.py | 17 - ...archive_billing_configurations_response.py | 19 - .../types/v1/customer_archive_params.py | 11 - .../types/v1/customer_archive_response.py | 10 - .../types/v1/customer_create_params.py | 158 - .../types/v1/customer_create_response.py | 10 - src/metronome/types/v1/customer_detail.py | 61 - .../customer_list_billable_metrics_params.py | 26 - ...customer_list_billable_metrics_response.py | 68 - .../types/v1/customer_list_costs_params.py | 27 - .../types/v1/customer_list_costs_response.py | 34 - .../types/v1/customer_list_params.py | 35 - .../v1/customer_preview_events_params.py | 46 - .../v1/customer_preview_events_response.py | 12 - ..._retrieve_billing_configurations_params.py | 13 - ...etrieve_billing_configurations_response.py | 56 - .../types/v1/customer_retrieve_response.py | 10 - ...tomer_set_billing_configurations_params.py | 63 - ...mer_set_billing_configurations_response.py | 48 - .../v1/customer_set_ingest_aliases_params.py | 15 - .../types/v1/customer_set_name_params.py | 17 - .../types/v1/customer_set_name_response.py | 10 - .../types/v1/customer_update_config_params.py | 21 - src/metronome/types/v1/customers/__init__.py | 40 - .../types/v1/customers/alert_list_params.py | 22 - .../types/v1/customers/alert_reset_params.py | 15 - .../v1/customers/alert_retrieve_params.py | 57 - .../v1/customers/alert_retrieve_response.py | 10 - .../customers/billing_config_create_params.py | 73 - .../billing_config_retrieve_response.py | 91 - .../v1/customers/commit_create_params.py | 226 -- .../v1/customers/commit_create_response.py | 10 - .../types/v1/customers/commit_list_params.py | 50 - .../commit_update_end_date_params.py | 32 - .../commit_update_end_date_response.py | 10 - .../v1/customers/credit_create_params.py | 100 - .../v1/customers/credit_create_response.py | 10 - .../types/v1/customers/credit_list_params.py | 50 - .../credit_update_end_date_params.py | 25 - .../credit_update_end_date_response.py | 10 - .../types/v1/customers/customer_alert.py | 150 - src/metronome/types/v1/customers/invoice.py | 604 ---- .../v1/customers/invoice_add_charge_params.py | 38 - .../customers/invoice_add_charge_response.py | 9 - .../invoice_list_breakdowns_params.py | 58 - .../invoice_list_breakdowns_response.py | 13 - .../types/v1/customers/invoice_list_params.py | 49 - .../v1/customers/invoice_retrieve_params.py | 16 - .../v1/customers/invoice_retrieve_response.py | 10 - .../named_schedule_retrieve_params.py | 25 - .../named_schedule_retrieve_response.py | 20 - .../customers/named_schedule_update_params.py | 29 - .../types/v1/customers/plan_add_params.py | 114 - .../types/v1/customers/plan_add_response.py | 10 - .../types/v1/customers/plan_end_params.py | 38 - .../types/v1/customers/plan_end_response.py | 9 - .../types/v1/customers/plan_list_params.py | 17 - .../plan_list_price_adjustments_params.py | 19 - .../plan_list_price_adjustments_response.py | 32 - .../types/v1/customers/plan_list_response.py | 46 - .../v1/dashboard_get_embeddable_url_params.py | 76 - .../dashboard_get_embeddable_url_response.py | 15 - .../types/v1/invoice_regenerate_params.py | 12 - .../types/v1/invoice_regenerate_response.py | 16 - src/metronome/types/v1/invoice_void_params.py | 12 - .../types/v1/invoice_void_response.py | 15 - .../types/v1/package_archive_params.py | 12 - .../types/v1/package_archive_response.py | 10 - .../types/v1/package_create_params.py | 1065 ------- .../types/v1/package_create_response.py | 10 - ...ackage_list_contracts_on_package_params.py | 38 - ...kage_list_contracts_on_package_response.py | 20 - src/metronome/types/v1/package_list_params.py | 18 - .../types/v1/package_list_response.py | 807 ----- .../types/v1/package_retrieve_params.py | 11 - .../types/v1/package_retrieve_response.py | 812 ----- src/metronome/types/v1/payment.py | 72 - .../types/v1/payment_attempt_params.py | 13 - .../types/v1/payment_attempt_response.py | 10 - .../types/v1/payment_cancel_params.py | 13 - .../types/v1/payment_cancel_response.py | 10 - src/metronome/types/v1/payment_list_params.py | 24 - src/metronome/types/v1/payment_status.py | 7 - src/metronome/types/v1/plan_detail.py | 77 - .../types/v1/plan_get_details_response.py | 10 - .../types/v1/plan_list_charges_params.py | 17 - .../types/v1/plan_list_charges_response.py | 72 - .../types/v1/plan_list_customers_params.py | 29 - .../types/v1/plan_list_customers_response.py | 32 - src/metronome/types/v1/plan_list_params.py | 15 - src/metronome/types/v1/plan_list_response.py | 18 - .../types/v1/pricing_unit_list_params.py | 15 - .../types/v1/pricing_unit_list_response.py | 15 - .../v1/rollover_amount_max_amount_param.py | 15 - .../rollover_amount_max_percentage_param.py | 15 - .../types/v1/service_list_response.py | 20 - ...tting_upsert_avalara_credentials_params.py | 32 - ...ing_upsert_avalara_credentials_response.py | 9 - src/metronome/types/v1/settings/__init__.py | 8 - .../billing_provider_create_params.py | 23 - .../billing_provider_create_response.py | 13 - .../settings/billing_provider_list_params.py | 13 - .../billing_provider_list_response.py | 42 - src/metronome/types/v1/usage_ingest_params.py | 25 - src/metronome/types/v1/usage_list_params.py | 58 - src/metronome/types/v1/usage_list_response.py | 28 - .../types/v1/usage_list_with_groups_params.py | 87 - .../v1/usage_list_with_groups_response.py | 30 - src/metronome/types/v1/usage_search_params.py | 15 - .../types/v1/usage_search_response.py | 111 - src/metronome/types/v2/__init__.py | 16 - .../types/v2/contract_edit_commit_params.py | 151 - .../types/v2/contract_edit_commit_response.py | 10 - .../types/v2/contract_edit_credit_params.py | 108 - .../types/v2/contract_edit_credit_response.py | 10 - .../types/v2/contract_edit_params.py | 1907 ----------- .../types/v2/contract_edit_response.py | 10 - .../v2/contract_get_edit_history_params.py | 13 - .../v2/contract_get_edit_history_response.py | 1239 ------- .../types/v2/contract_list_params.py | 44 - .../types/v2/contract_list_response.py | 12 - .../types/v2/contract_retrieve_params.py | 37 - .../types/v2/contract_retrieve_response.py | 10 - 351 files changed, 52127 deletions(-) delete mode 100644 src/metronome/__init__.py delete mode 100644 src/metronome/_base_client.py delete mode 100644 src/metronome/_client.py delete mode 100644 src/metronome/_compat.py delete mode 100644 src/metronome/_constants.py delete mode 100644 src/metronome/_exceptions.py delete mode 100644 src/metronome/_files.py delete mode 100644 src/metronome/_models.py delete mode 100644 src/metronome/_qs.py delete mode 100644 src/metronome/_resource.py delete mode 100644 src/metronome/_response.py delete mode 100644 src/metronome/_streaming.py delete mode 100644 src/metronome/_types.py delete mode 100644 src/metronome/_utils/__init__.py delete mode 100644 src/metronome/_utils/_compat.py delete mode 100644 src/metronome/_utils/_datetime_parse.py delete mode 100644 src/metronome/_utils/_json.py delete mode 100644 src/metronome/_utils/_logs.py delete mode 100644 src/metronome/_utils/_proxy.py delete mode 100644 src/metronome/_utils/_reflection.py delete mode 100644 src/metronome/_utils/_resources_proxy.py delete mode 100644 src/metronome/_utils/_streams.py delete mode 100644 src/metronome/_utils/_sync.py delete mode 100644 src/metronome/_utils/_transform.py delete mode 100644 src/metronome/_utils/_typing.py delete mode 100644 src/metronome/_utils/_utils.py delete mode 100644 src/metronome/_version.py delete mode 100644 src/metronome/lib/.keep delete mode 100644 src/metronome/pagination.py delete mode 100644 src/metronome/py.typed delete mode 100644 src/metronome/resources/__init__.py delete mode 100644 src/metronome/resources/v1/__init__.py delete mode 100644 src/metronome/resources/v1/alerts.py delete mode 100644 src/metronome/resources/v1/audit_logs.py delete mode 100644 src/metronome/resources/v1/billable_metrics.py delete mode 100644 src/metronome/resources/v1/contracts/__init__.py delete mode 100644 src/metronome/resources/v1/contracts/contracts.py delete mode 100644 src/metronome/resources/v1/contracts/named_schedules.py delete mode 100644 src/metronome/resources/v1/contracts/products.py delete mode 100644 src/metronome/resources/v1/contracts/rate_cards/__init__.py delete mode 100644 src/metronome/resources/v1/contracts/rate_cards/named_schedules.py delete mode 100644 src/metronome/resources/v1/contracts/rate_cards/product_orders.py delete mode 100644 src/metronome/resources/v1/contracts/rate_cards/rate_cards.py delete mode 100644 src/metronome/resources/v1/contracts/rate_cards/rates.py delete mode 100644 src/metronome/resources/v1/credit_grants.py delete mode 100644 src/metronome/resources/v1/custom_fields.py delete mode 100644 src/metronome/resources/v1/customers/__init__.py delete mode 100644 src/metronome/resources/v1/customers/alerts.py delete mode 100644 src/metronome/resources/v1/customers/billing_config.py delete mode 100644 src/metronome/resources/v1/customers/commits.py delete mode 100644 src/metronome/resources/v1/customers/credits.py delete mode 100644 src/metronome/resources/v1/customers/customers.py delete mode 100644 src/metronome/resources/v1/customers/invoices.py delete mode 100644 src/metronome/resources/v1/customers/named_schedules.py delete mode 100644 src/metronome/resources/v1/customers/plans.py delete mode 100644 src/metronome/resources/v1/dashboards.py delete mode 100644 src/metronome/resources/v1/invoices.py delete mode 100644 src/metronome/resources/v1/packages.py delete mode 100644 src/metronome/resources/v1/payments.py delete mode 100644 src/metronome/resources/v1/plans.py delete mode 100644 src/metronome/resources/v1/pricing_units.py delete mode 100644 src/metronome/resources/v1/services.py delete mode 100644 src/metronome/resources/v1/settings/__init__.py delete mode 100644 src/metronome/resources/v1/settings/billing_providers.py delete mode 100644 src/metronome/resources/v1/settings/settings.py delete mode 100644 src/metronome/resources/v1/usage.py delete mode 100644 src/metronome/resources/v1/v1.py delete mode 100644 src/metronome/resources/v2/__init__.py delete mode 100644 src/metronome/resources/v2/contracts.py delete mode 100644 src/metronome/resources/v2/v2.py delete mode 100644 src/metronome/types/__init__.py delete mode 100644 src/metronome/types/shared/__init__.py delete mode 100644 src/metronome/types/shared/balance_filter.py delete mode 100644 src/metronome/types/shared/base_threshold_commit.py delete mode 100644 src/metronome/types/shared/base_usage_filter.py delete mode 100644 src/metronome/types/shared/commit.py delete mode 100644 src/metronome/types/shared/commit_hierarchy_configuration.py delete mode 100644 src/metronome/types/shared/commit_rate.py delete mode 100644 src/metronome/types/shared/commit_specifier.py delete mode 100644 src/metronome/types/shared/commit_specifier_input.py delete mode 100644 src/metronome/types/shared/contract.py delete mode 100644 src/metronome/types/shared/contract_v2.py delete mode 100644 src/metronome/types/shared/contract_without_amendments.py delete mode 100644 src/metronome/types/shared/credit.py delete mode 100644 src/metronome/types/shared/credit_type_data.py delete mode 100644 src/metronome/types/shared/discount.py delete mode 100644 src/metronome/types/shared/event_type_filter.py delete mode 100644 src/metronome/types/shared/hierarchy_configuration.py delete mode 100644 src/metronome/types/shared/id.py delete mode 100644 src/metronome/types/shared/override.py delete mode 100644 src/metronome/types/shared/override_tier.py delete mode 100644 src/metronome/types/shared/overwrite_rate.py delete mode 100644 src/metronome/types/shared/payment_gate_config.py delete mode 100644 src/metronome/types/shared/payment_gate_config_v2.py delete mode 100644 src/metronome/types/shared/prepaid_balance_threshold_configuration.py delete mode 100644 src/metronome/types/shared/prepaid_balance_threshold_configuration_v2.py delete mode 100644 src/metronome/types/shared/pro_service.py delete mode 100644 src/metronome/types/shared/property_filter.py delete mode 100644 src/metronome/types/shared/rate.py delete mode 100644 src/metronome/types/shared/recurring_commit_subscription_config.py delete mode 100644 src/metronome/types/shared/schedule_duration.py delete mode 100644 src/metronome/types/shared/schedule_point_in_time.py delete mode 100644 src/metronome/types/shared/scheduled_charge.py delete mode 100644 src/metronome/types/shared/spend_threshold_configuration.py delete mode 100644 src/metronome/types/shared/spend_threshold_configuration_v2.py delete mode 100644 src/metronome/types/shared/subscription.py delete mode 100644 src/metronome/types/shared/tier.py delete mode 100644 src/metronome/types/shared/update_base_threshold_commit.py delete mode 100644 src/metronome/types/shared_params/__init__.py delete mode 100644 src/metronome/types/shared_params/balance_filter.py delete mode 100644 src/metronome/types/shared_params/base_threshold_commit.py delete mode 100644 src/metronome/types/shared_params/base_usage_filter.py delete mode 100644 src/metronome/types/shared_params/commit_hierarchy_configuration.py delete mode 100644 src/metronome/types/shared_params/commit_rate.py delete mode 100644 src/metronome/types/shared_params/commit_specifier_input.py delete mode 100644 src/metronome/types/shared_params/event_type_filter.py delete mode 100644 src/metronome/types/shared_params/payment_gate_config.py delete mode 100644 src/metronome/types/shared_params/payment_gate_config_v2.py delete mode 100644 src/metronome/types/shared_params/prepaid_balance_threshold_configuration.py delete mode 100644 src/metronome/types/shared_params/prepaid_balance_threshold_configuration_v2.py delete mode 100644 src/metronome/types/shared_params/property_filter.py delete mode 100644 src/metronome/types/shared_params/spend_threshold_configuration.py delete mode 100644 src/metronome/types/shared_params/spend_threshold_configuration_v2.py delete mode 100644 src/metronome/types/shared_params/tier.py delete mode 100644 src/metronome/types/shared_params/update_base_threshold_commit.py delete mode 100644 src/metronome/types/v1/__init__.py delete mode 100644 src/metronome/types/v1/alert_archive_params.py delete mode 100644 src/metronome/types/v1/alert_archive_response.py delete mode 100644 src/metronome/types/v1/alert_create_params.py delete mode 100644 src/metronome/types/v1/alert_create_response.py delete mode 100644 src/metronome/types/v1/audit_log_list_params.py delete mode 100644 src/metronome/types/v1/audit_log_list_response.py delete mode 100644 src/metronome/types/v1/billable_metric_archive_params.py delete mode 100644 src/metronome/types/v1/billable_metric_archive_response.py delete mode 100644 src/metronome/types/v1/billable_metric_create_params.py delete mode 100644 src/metronome/types/v1/billable_metric_create_response.py delete mode 100644 src/metronome/types/v1/billable_metric_list_params.py delete mode 100644 src/metronome/types/v1/billable_metric_list_response.py delete mode 100644 src/metronome/types/v1/billable_metric_retrieve_response.py delete mode 100644 src/metronome/types/v1/contract_add_manual_balance_entry_params.py delete mode 100644 src/metronome/types/v1/contract_amend_params.py delete mode 100644 src/metronome/types/v1/contract_amend_response.py delete mode 100644 src/metronome/types/v1/contract_archive_params.py delete mode 100644 src/metronome/types/v1/contract_archive_response.py delete mode 100644 src/metronome/types/v1/contract_create_historical_invoices_params.py delete mode 100644 src/metronome/types/v1/contract_create_historical_invoices_response.py delete mode 100644 src/metronome/types/v1/contract_create_params.py delete mode 100644 src/metronome/types/v1/contract_create_response.py delete mode 100644 src/metronome/types/v1/contract_get_net_balance_params.py delete mode 100644 src/metronome/types/v1/contract_get_net_balance_response.py delete mode 100644 src/metronome/types/v1/contract_list_balances_params.py delete mode 100644 src/metronome/types/v1/contract_list_balances_response.py delete mode 100644 src/metronome/types/v1/contract_list_params.py delete mode 100644 src/metronome/types/v1/contract_list_response.py delete mode 100644 src/metronome/types/v1/contract_retrieve_params.py delete mode 100644 src/metronome/types/v1/contract_retrieve_rate_schedule_params.py delete mode 100644 src/metronome/types/v1/contract_retrieve_rate_schedule_response.py delete mode 100644 src/metronome/types/v1/contract_retrieve_response.py delete mode 100644 src/metronome/types/v1/contract_retrieve_subscription_quantity_history_params.py delete mode 100644 src/metronome/types/v1/contract_retrieve_subscription_quantity_history_response.py delete mode 100644 src/metronome/types/v1/contract_schedule_pro_services_invoice_params.py delete mode 100644 src/metronome/types/v1/contract_schedule_pro_services_invoice_response.py delete mode 100644 src/metronome/types/v1/contract_set_usage_filter_params.py delete mode 100644 src/metronome/types/v1/contract_update_end_date_params.py delete mode 100644 src/metronome/types/v1/contract_update_end_date_response.py delete mode 100644 src/metronome/types/v1/contracts/__init__.py delete mode 100644 src/metronome/types/v1/contracts/named_schedule_retrieve_params.py delete mode 100644 src/metronome/types/v1/contracts/named_schedule_retrieve_response.py delete mode 100644 src/metronome/types/v1/contracts/named_schedule_update_params.py delete mode 100644 src/metronome/types/v1/contracts/product_archive_params.py delete mode 100644 src/metronome/types/v1/contracts/product_archive_response.py delete mode 100644 src/metronome/types/v1/contracts/product_create_params.py delete mode 100644 src/metronome/types/v1/contracts/product_create_response.py delete mode 100644 src/metronome/types/v1/contracts/product_list_item_state.py delete mode 100644 src/metronome/types/v1/contracts/product_list_params.py delete mode 100644 src/metronome/types/v1/contracts/product_list_response.py delete mode 100644 src/metronome/types/v1/contracts/product_retrieve_params.py delete mode 100644 src/metronome/types/v1/contracts/product_retrieve_response.py delete mode 100644 src/metronome/types/v1/contracts/product_update_params.py delete mode 100644 src/metronome/types/v1/contracts/product_update_response.py delete mode 100644 src/metronome/types/v1/contracts/quantity_conversion.py delete mode 100644 src/metronome/types/v1/contracts/quantity_conversion_param.py delete mode 100644 src/metronome/types/v1/contracts/quantity_rounding.py delete mode 100644 src/metronome/types/v1/contracts/quantity_rounding_param.py delete mode 100644 src/metronome/types/v1/contracts/rate_card_archive_params.py delete mode 100644 src/metronome/types/v1/contracts/rate_card_archive_response.py delete mode 100644 src/metronome/types/v1/contracts/rate_card_create_params.py delete mode 100644 src/metronome/types/v1/contracts/rate_card_create_response.py delete mode 100644 src/metronome/types/v1/contracts/rate_card_list_params.py delete mode 100644 src/metronome/types/v1/contracts/rate_card_list_response.py delete mode 100644 src/metronome/types/v1/contracts/rate_card_retrieve_params.py delete mode 100644 src/metronome/types/v1/contracts/rate_card_retrieve_rate_schedule_params.py delete mode 100644 src/metronome/types/v1/contracts/rate_card_retrieve_rate_schedule_response.py delete mode 100644 src/metronome/types/v1/contracts/rate_card_retrieve_response.py delete mode 100644 src/metronome/types/v1/contracts/rate_card_update_params.py delete mode 100644 src/metronome/types/v1/contracts/rate_card_update_response.py delete mode 100644 src/metronome/types/v1/contracts/rate_cards/__init__.py delete mode 100644 src/metronome/types/v1/contracts/rate_cards/named_schedule_retrieve_params.py delete mode 100644 src/metronome/types/v1/contracts/rate_cards/named_schedule_retrieve_response.py delete mode 100644 src/metronome/types/v1/contracts/rate_cards/named_schedule_update_params.py delete mode 100644 src/metronome/types/v1/contracts/rate_cards/product_order_set_params.py delete mode 100644 src/metronome/types/v1/contracts/rate_cards/product_order_set_response.py delete mode 100644 src/metronome/types/v1/contracts/rate_cards/product_order_update_params.py delete mode 100644 src/metronome/types/v1/contracts/rate_cards/product_order_update_response.py delete mode 100644 src/metronome/types/v1/contracts/rate_cards/rate_add_many_params.py delete mode 100644 src/metronome/types/v1/contracts/rate_cards/rate_add_many_response.py delete mode 100644 src/metronome/types/v1/contracts/rate_cards/rate_add_params.py delete mode 100644 src/metronome/types/v1/contracts/rate_cards/rate_add_response.py delete mode 100644 src/metronome/types/v1/contracts/rate_cards/rate_list_params.py delete mode 100644 src/metronome/types/v1/contracts/rate_cards/rate_list_response.py delete mode 100644 src/metronome/types/v1/credit_grant_create_params.py delete mode 100644 src/metronome/types/v1/credit_grant_create_response.py delete mode 100644 src/metronome/types/v1/credit_grant_edit_params.py delete mode 100644 src/metronome/types/v1/credit_grant_edit_response.py delete mode 100644 src/metronome/types/v1/credit_grant_list_entries_params.py delete mode 100644 src/metronome/types/v1/credit_grant_list_entries_response.py delete mode 100644 src/metronome/types/v1/credit_grant_list_params.py delete mode 100644 src/metronome/types/v1/credit_grant_list_response.py delete mode 100644 src/metronome/types/v1/credit_grant_void_params.py delete mode 100644 src/metronome/types/v1/credit_grant_void_response.py delete mode 100644 src/metronome/types/v1/credit_ledger_entry.py delete mode 100644 src/metronome/types/v1/custom_field_add_key_params.py delete mode 100644 src/metronome/types/v1/custom_field_delete_values_params.py delete mode 100644 src/metronome/types/v1/custom_field_list_keys_params.py delete mode 100644 src/metronome/types/v1/custom_field_list_keys_response.py delete mode 100644 src/metronome/types/v1/custom_field_remove_key_params.py delete mode 100644 src/metronome/types/v1/custom_field_set_values_params.py delete mode 100644 src/metronome/types/v1/customer.py delete mode 100644 src/metronome/types/v1/customer_archive_billing_configurations_params.py delete mode 100644 src/metronome/types/v1/customer_archive_billing_configurations_response.py delete mode 100644 src/metronome/types/v1/customer_archive_params.py delete mode 100644 src/metronome/types/v1/customer_archive_response.py delete mode 100644 src/metronome/types/v1/customer_create_params.py delete mode 100644 src/metronome/types/v1/customer_create_response.py delete mode 100644 src/metronome/types/v1/customer_detail.py delete mode 100644 src/metronome/types/v1/customer_list_billable_metrics_params.py delete mode 100644 src/metronome/types/v1/customer_list_billable_metrics_response.py delete mode 100644 src/metronome/types/v1/customer_list_costs_params.py delete mode 100644 src/metronome/types/v1/customer_list_costs_response.py delete mode 100644 src/metronome/types/v1/customer_list_params.py delete mode 100644 src/metronome/types/v1/customer_preview_events_params.py delete mode 100644 src/metronome/types/v1/customer_preview_events_response.py delete mode 100644 src/metronome/types/v1/customer_retrieve_billing_configurations_params.py delete mode 100644 src/metronome/types/v1/customer_retrieve_billing_configurations_response.py delete mode 100644 src/metronome/types/v1/customer_retrieve_response.py delete mode 100644 src/metronome/types/v1/customer_set_billing_configurations_params.py delete mode 100644 src/metronome/types/v1/customer_set_billing_configurations_response.py delete mode 100644 src/metronome/types/v1/customer_set_ingest_aliases_params.py delete mode 100644 src/metronome/types/v1/customer_set_name_params.py delete mode 100644 src/metronome/types/v1/customer_set_name_response.py delete mode 100644 src/metronome/types/v1/customer_update_config_params.py delete mode 100644 src/metronome/types/v1/customers/__init__.py delete mode 100644 src/metronome/types/v1/customers/alert_list_params.py delete mode 100644 src/metronome/types/v1/customers/alert_reset_params.py delete mode 100644 src/metronome/types/v1/customers/alert_retrieve_params.py delete mode 100644 src/metronome/types/v1/customers/alert_retrieve_response.py delete mode 100644 src/metronome/types/v1/customers/billing_config_create_params.py delete mode 100644 src/metronome/types/v1/customers/billing_config_retrieve_response.py delete mode 100644 src/metronome/types/v1/customers/commit_create_params.py delete mode 100644 src/metronome/types/v1/customers/commit_create_response.py delete mode 100644 src/metronome/types/v1/customers/commit_list_params.py delete mode 100644 src/metronome/types/v1/customers/commit_update_end_date_params.py delete mode 100644 src/metronome/types/v1/customers/commit_update_end_date_response.py delete mode 100644 src/metronome/types/v1/customers/credit_create_params.py delete mode 100644 src/metronome/types/v1/customers/credit_create_response.py delete mode 100644 src/metronome/types/v1/customers/credit_list_params.py delete mode 100644 src/metronome/types/v1/customers/credit_update_end_date_params.py delete mode 100644 src/metronome/types/v1/customers/credit_update_end_date_response.py delete mode 100644 src/metronome/types/v1/customers/customer_alert.py delete mode 100644 src/metronome/types/v1/customers/invoice.py delete mode 100644 src/metronome/types/v1/customers/invoice_add_charge_params.py delete mode 100644 src/metronome/types/v1/customers/invoice_add_charge_response.py delete mode 100644 src/metronome/types/v1/customers/invoice_list_breakdowns_params.py delete mode 100644 src/metronome/types/v1/customers/invoice_list_breakdowns_response.py delete mode 100644 src/metronome/types/v1/customers/invoice_list_params.py delete mode 100644 src/metronome/types/v1/customers/invoice_retrieve_params.py delete mode 100644 src/metronome/types/v1/customers/invoice_retrieve_response.py delete mode 100644 src/metronome/types/v1/customers/named_schedule_retrieve_params.py delete mode 100644 src/metronome/types/v1/customers/named_schedule_retrieve_response.py delete mode 100644 src/metronome/types/v1/customers/named_schedule_update_params.py delete mode 100644 src/metronome/types/v1/customers/plan_add_params.py delete mode 100644 src/metronome/types/v1/customers/plan_add_response.py delete mode 100644 src/metronome/types/v1/customers/plan_end_params.py delete mode 100644 src/metronome/types/v1/customers/plan_end_response.py delete mode 100644 src/metronome/types/v1/customers/plan_list_params.py delete mode 100644 src/metronome/types/v1/customers/plan_list_price_adjustments_params.py delete mode 100644 src/metronome/types/v1/customers/plan_list_price_adjustments_response.py delete mode 100644 src/metronome/types/v1/customers/plan_list_response.py delete mode 100644 src/metronome/types/v1/dashboard_get_embeddable_url_params.py delete mode 100644 src/metronome/types/v1/dashboard_get_embeddable_url_response.py delete mode 100644 src/metronome/types/v1/invoice_regenerate_params.py delete mode 100644 src/metronome/types/v1/invoice_regenerate_response.py delete mode 100644 src/metronome/types/v1/invoice_void_params.py delete mode 100644 src/metronome/types/v1/invoice_void_response.py delete mode 100644 src/metronome/types/v1/package_archive_params.py delete mode 100644 src/metronome/types/v1/package_archive_response.py delete mode 100644 src/metronome/types/v1/package_create_params.py delete mode 100644 src/metronome/types/v1/package_create_response.py delete mode 100644 src/metronome/types/v1/package_list_contracts_on_package_params.py delete mode 100644 src/metronome/types/v1/package_list_contracts_on_package_response.py delete mode 100644 src/metronome/types/v1/package_list_params.py delete mode 100644 src/metronome/types/v1/package_list_response.py delete mode 100644 src/metronome/types/v1/package_retrieve_params.py delete mode 100644 src/metronome/types/v1/package_retrieve_response.py delete mode 100644 src/metronome/types/v1/payment.py delete mode 100644 src/metronome/types/v1/payment_attempt_params.py delete mode 100644 src/metronome/types/v1/payment_attempt_response.py delete mode 100644 src/metronome/types/v1/payment_cancel_params.py delete mode 100644 src/metronome/types/v1/payment_cancel_response.py delete mode 100644 src/metronome/types/v1/payment_list_params.py delete mode 100644 src/metronome/types/v1/payment_status.py delete mode 100644 src/metronome/types/v1/plan_detail.py delete mode 100644 src/metronome/types/v1/plan_get_details_response.py delete mode 100644 src/metronome/types/v1/plan_list_charges_params.py delete mode 100644 src/metronome/types/v1/plan_list_charges_response.py delete mode 100644 src/metronome/types/v1/plan_list_customers_params.py delete mode 100644 src/metronome/types/v1/plan_list_customers_response.py delete mode 100644 src/metronome/types/v1/plan_list_params.py delete mode 100644 src/metronome/types/v1/plan_list_response.py delete mode 100644 src/metronome/types/v1/pricing_unit_list_params.py delete mode 100644 src/metronome/types/v1/pricing_unit_list_response.py delete mode 100644 src/metronome/types/v1/rollover_amount_max_amount_param.py delete mode 100644 src/metronome/types/v1/rollover_amount_max_percentage_param.py delete mode 100644 src/metronome/types/v1/service_list_response.py delete mode 100644 src/metronome/types/v1/setting_upsert_avalara_credentials_params.py delete mode 100644 src/metronome/types/v1/setting_upsert_avalara_credentials_response.py delete mode 100644 src/metronome/types/v1/settings/__init__.py delete mode 100644 src/metronome/types/v1/settings/billing_provider_create_params.py delete mode 100644 src/metronome/types/v1/settings/billing_provider_create_response.py delete mode 100644 src/metronome/types/v1/settings/billing_provider_list_params.py delete mode 100644 src/metronome/types/v1/settings/billing_provider_list_response.py delete mode 100644 src/metronome/types/v1/usage_ingest_params.py delete mode 100644 src/metronome/types/v1/usage_list_params.py delete mode 100644 src/metronome/types/v1/usage_list_response.py delete mode 100644 src/metronome/types/v1/usage_list_with_groups_params.py delete mode 100644 src/metronome/types/v1/usage_list_with_groups_response.py delete mode 100644 src/metronome/types/v1/usage_search_params.py delete mode 100644 src/metronome/types/v1/usage_search_response.py delete mode 100644 src/metronome/types/v2/__init__.py delete mode 100644 src/metronome/types/v2/contract_edit_commit_params.py delete mode 100644 src/metronome/types/v2/contract_edit_commit_response.py delete mode 100644 src/metronome/types/v2/contract_edit_credit_params.py delete mode 100644 src/metronome/types/v2/contract_edit_credit_response.py delete mode 100644 src/metronome/types/v2/contract_edit_params.py delete mode 100644 src/metronome/types/v2/contract_edit_response.py delete mode 100644 src/metronome/types/v2/contract_get_edit_history_params.py delete mode 100644 src/metronome/types/v2/contract_get_edit_history_response.py delete mode 100644 src/metronome/types/v2/contract_list_params.py delete mode 100644 src/metronome/types/v2/contract_list_response.py delete mode 100644 src/metronome/types/v2/contract_retrieve_params.py delete mode 100644 src/metronome/types/v2/contract_retrieve_response.py diff --git a/src/metronome/__init__.py b/src/metronome/__init__.py deleted file mode 100644 index b83152799..000000000 --- a/src/metronome/__init__.py +++ /dev/null @@ -1,102 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import typing as _t - -from . import types -from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes, omit, not_given -from ._utils import file_from_path -from ._client import ( - Client, - Stream, - Timeout, - Metronome, - Transport, - AsyncClient, - AsyncStream, - AsyncMetronome, - RequestOptions, -) -from ._models import BaseModel -from ._version import __title__, __version__ -from ._response import APIResponse as APIResponse, AsyncAPIResponse as AsyncAPIResponse -from ._constants import DEFAULT_TIMEOUT, DEFAULT_MAX_RETRIES, DEFAULT_CONNECTION_LIMITS -from ._exceptions import ( - APIError, - ConflictError, - NotFoundError, - APIStatusError, - MetronomeError, - RateLimitError, - APITimeoutError, - BadRequestError, - APIConnectionError, - AuthenticationError, - InternalServerError, - PermissionDeniedError, - UnprocessableEntityError, - APIResponseValidationError, -) -from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient -from ._utils._logs import setup_logging as _setup_logging - -__all__ = [ - "types", - "__version__", - "__title__", - "NoneType", - "Transport", - "ProxiesTypes", - "NotGiven", - "NOT_GIVEN", - "not_given", - "Omit", - "omit", - "MetronomeError", - "APIError", - "APIStatusError", - "APITimeoutError", - "APIConnectionError", - "APIResponseValidationError", - "BadRequestError", - "AuthenticationError", - "PermissionDeniedError", - "NotFoundError", - "ConflictError", - "UnprocessableEntityError", - "RateLimitError", - "InternalServerError", - "Timeout", - "RequestOptions", - "Client", - "AsyncClient", - "Stream", - "AsyncStream", - "Metronome", - "AsyncMetronome", - "file_from_path", - "BaseModel", - "DEFAULT_TIMEOUT", - "DEFAULT_MAX_RETRIES", - "DEFAULT_CONNECTION_LIMITS", - "DefaultHttpxClient", - "DefaultAsyncHttpxClient", - "DefaultAioHttpClient", -] - -if not _t.TYPE_CHECKING: - from ._utils._resources_proxy import resources as resources - -_setup_logging() - -# Update the __module__ attribute for exported symbols so that -# error messages point to this module instead of the module -# it was originally defined in, e.g. -# metronome._exceptions.NotFoundError -> metronome.NotFoundError -__locals = locals() -for __name in __all__: - if not __name.startswith("__"): - try: - __locals[__name].__module__ = "metronome" - except (TypeError, AttributeError): - # Some of our exported symbols are builtins which we can't set attributes for. - pass diff --git a/src/metronome/_base_client.py b/src/metronome/_base_client.py deleted file mode 100644 index aeee5394d..000000000 --- a/src/metronome/_base_client.py +++ /dev/null @@ -1,2127 +0,0 @@ -from __future__ import annotations - -import sys -import json -import time -import uuid -import email -import asyncio -import inspect -import logging -import platform -import warnings -import email.utils -from types import TracebackType -from random import random -from typing import ( - TYPE_CHECKING, - Any, - Dict, - Type, - Union, - Generic, - Mapping, - TypeVar, - Iterable, - Iterator, - Optional, - Generator, - AsyncIterator, - cast, - overload, -) -from typing_extensions import Literal, override, get_origin - -import anyio -import httpx -import distro -import pydantic -from httpx import URL -from pydantic import PrivateAttr - -from . import _exceptions -from ._qs import Querystring -from ._files import to_httpx_files, async_to_httpx_files -from ._types import ( - Body, - Omit, - Query, - Headers, - Timeout, - NotGiven, - ResponseT, - AnyMapping, - PostParser, - BinaryTypes, - RequestFiles, - HttpxSendArgs, - RequestOptions, - AsyncBinaryTypes, - HttpxRequestFiles, - ModelBuilderProtocol, - not_given, -) -from ._utils import is_dict, is_list, asyncify, is_given, lru_cache, is_mapping -from ._compat import PYDANTIC_V1, model_copy, model_dump -from ._models import GenericModel, FinalRequestOptions, validate_type, construct_type -from ._response import ( - APIResponse, - BaseAPIResponse, - AsyncAPIResponse, - extract_response_type, -) -from ._constants import ( - DEFAULT_TIMEOUT, - MAX_RETRY_DELAY, - DEFAULT_MAX_RETRIES, - INITIAL_RETRY_DELAY, - RAW_RESPONSE_HEADER, - OVERRIDE_CAST_TO_HEADER, - DEFAULT_CONNECTION_LIMITS, -) -from ._streaming import Stream, SSEDecoder, AsyncStream, SSEBytesDecoder -from ._exceptions import ( - APIStatusError, - APITimeoutError, - APIConnectionError, - APIResponseValidationError, -) -from ._utils._json import openapi_dumps - -log: logging.Logger = logging.getLogger(__name__) - -# TODO: make base page type vars covariant -SyncPageT = TypeVar("SyncPageT", bound="BaseSyncPage[Any]") -AsyncPageT = TypeVar("AsyncPageT", bound="BaseAsyncPage[Any]") - - -_T = TypeVar("_T") -_T_co = TypeVar("_T_co", covariant=True) - -_StreamT = TypeVar("_StreamT", bound=Stream[Any]) -_AsyncStreamT = TypeVar("_AsyncStreamT", bound=AsyncStream[Any]) - -if TYPE_CHECKING: - from httpx._config import ( - DEFAULT_TIMEOUT_CONFIG, # pyright: ignore[reportPrivateImportUsage] - ) - - HTTPX_DEFAULT_TIMEOUT = DEFAULT_TIMEOUT_CONFIG -else: - try: - from httpx._config import DEFAULT_TIMEOUT_CONFIG as HTTPX_DEFAULT_TIMEOUT - except ImportError: - # taken from https://github.com/encode/httpx/blob/3ba5fe0d7ac70222590e759c31442b1cab263791/httpx/_config.py#L366 - HTTPX_DEFAULT_TIMEOUT = Timeout(5.0) - - -class PageInfo: - """Stores the necessary information to build the request to retrieve the next page. - - Either `url` or `params` must be set. - """ - - url: URL | NotGiven - params: Query | NotGiven - json: Body | NotGiven - - @overload - def __init__( - self, - *, - url: URL, - ) -> None: ... - - @overload - def __init__( - self, - *, - params: Query, - ) -> None: ... - - @overload - def __init__( - self, - *, - json: Body, - ) -> None: ... - - def __init__( - self, - *, - url: URL | NotGiven = not_given, - json: Body | NotGiven = not_given, - params: Query | NotGiven = not_given, - ) -> None: - self.url = url - self.json = json - self.params = params - - @override - def __repr__(self) -> str: - if self.url: - return f"{self.__class__.__name__}(url={self.url})" - if self.json: - return f"{self.__class__.__name__}(json={self.json})" - return f"{self.__class__.__name__}(params={self.params})" - - -class BasePage(GenericModel, Generic[_T]): - """ - Defines the core interface for pagination. - - Type Args: - ModelT: The pydantic model that represents an item in the response. - - Methods: - has_next_page(): Check if there is another page available - next_page_info(): Get the necessary information to make a request for the next page - """ - - _options: FinalRequestOptions = PrivateAttr() - _model: Type[_T] = PrivateAttr() - - def has_next_page(self) -> bool: - items = self._get_page_items() - if not items: - return False - return self.next_page_info() is not None - - def next_page_info(self) -> Optional[PageInfo]: ... - - def _get_page_items(self) -> Iterable[_T]: # type: ignore[empty-body] - ... - - def _params_from_url(self, url: URL) -> httpx.QueryParams: - # TODO: do we have to preprocess params here? - return httpx.QueryParams(cast(Any, self._options.params)).merge(url.params) - - def _info_to_options(self, info: PageInfo) -> FinalRequestOptions: - options = model_copy(self._options) - options._strip_raw_response_header() - - if not isinstance(info.params, NotGiven): - options.params = {**options.params, **info.params} - return options - - if not isinstance(info.url, NotGiven): - params = self._params_from_url(info.url) - url = info.url.copy_with(params=params) - options.params = dict(url.params) - options.url = str(url) - return options - - if not isinstance(info.json, NotGiven): - if not is_mapping(info.json): - raise TypeError("Pagination is only supported with mappings") - - if not options.json_data: - options.json_data = {**info.json} - else: - if not is_mapping(options.json_data): - raise TypeError("Pagination is only supported with mappings") - - options.json_data = {**options.json_data, **info.json} - return options - - raise ValueError("Unexpected PageInfo state") - - -class BaseSyncPage(BasePage[_T], Generic[_T]): - _client: SyncAPIClient = pydantic.PrivateAttr() - - def _set_private_attributes( - self, - client: SyncAPIClient, - model: Type[_T], - options: FinalRequestOptions, - ) -> None: - if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None: - self.__pydantic_private__ = {} - - self._model = model - self._client = client - self._options = options - - # Pydantic uses a custom `__iter__` method to support casting BaseModels - # to dictionaries. e.g. dict(model). - # As we want to support `for item in page`, this is inherently incompatible - # with the default pydantic behaviour. It is not possible to support both - # use cases at once. Fortunately, this is not a big deal as all other pydantic - # methods should continue to work as expected as there is an alternative method - # to cast a model to a dictionary, model.dict(), which is used internally - # by pydantic. - def __iter__(self) -> Iterator[_T]: # type: ignore - for page in self.iter_pages(): - for item in page._get_page_items(): - yield item - - def iter_pages(self: SyncPageT) -> Iterator[SyncPageT]: - page = self - while True: - yield page - if page.has_next_page(): - page = page.get_next_page() - else: - return - - def get_next_page(self: SyncPageT) -> SyncPageT: - info = self.next_page_info() - if not info: - raise RuntimeError( - "No next page expected; please check `.has_next_page()` before calling `.get_next_page()`." - ) - - options = self._info_to_options(info) - return self._client._request_api_list(self._model, page=self.__class__, options=options) - - -class AsyncPaginator(Generic[_T, AsyncPageT]): - def __init__( - self, - client: AsyncAPIClient, - options: FinalRequestOptions, - page_cls: Type[AsyncPageT], - model: Type[_T], - ) -> None: - self._model = model - self._client = client - self._options = options - self._page_cls = page_cls - - def __await__(self) -> Generator[Any, None, AsyncPageT]: - return self._get_page().__await__() - - async def _get_page(self) -> AsyncPageT: - def _parser(resp: AsyncPageT) -> AsyncPageT: - resp._set_private_attributes( - model=self._model, - options=self._options, - client=self._client, - ) - return resp - - self._options.post_parser = _parser - - return await self._client.request(self._page_cls, self._options) - - async def __aiter__(self) -> AsyncIterator[_T]: - # https://github.com/microsoft/pyright/issues/3464 - page = cast( - AsyncPageT, - await self, # type: ignore - ) - async for item in page: - yield item - - -class BaseAsyncPage(BasePage[_T], Generic[_T]): - _client: AsyncAPIClient = pydantic.PrivateAttr() - - def _set_private_attributes( - self, - model: Type[_T], - client: AsyncAPIClient, - options: FinalRequestOptions, - ) -> None: - if (not PYDANTIC_V1) and getattr(self, "__pydantic_private__", None) is None: - self.__pydantic_private__ = {} - - self._model = model - self._client = client - self._options = options - - async def __aiter__(self) -> AsyncIterator[_T]: - async for page in self.iter_pages(): - for item in page._get_page_items(): - yield item - - async def iter_pages(self: AsyncPageT) -> AsyncIterator[AsyncPageT]: - page = self - while True: - yield page - if page.has_next_page(): - page = await page.get_next_page() - else: - return - - async def get_next_page(self: AsyncPageT) -> AsyncPageT: - info = self.next_page_info() - if not info: - raise RuntimeError( - "No next page expected; please check `.has_next_page()` before calling `.get_next_page()`." - ) - - options = self._info_to_options(info) - return await self._client._request_api_list(self._model, page=self.__class__, options=options) - - -_HttpxClientT = TypeVar("_HttpxClientT", bound=Union[httpx.Client, httpx.AsyncClient]) -_DefaultStreamT = TypeVar("_DefaultStreamT", bound=Union[Stream[Any], AsyncStream[Any]]) - - -class BaseClient(Generic[_HttpxClientT, _DefaultStreamT]): - _client: _HttpxClientT - _version: str - _base_url: URL - max_retries: int - timeout: Union[float, Timeout, None] - _strict_response_validation: bool - _idempotency_header: str | None - _default_stream_cls: type[_DefaultStreamT] | None = None - - def __init__( - self, - *, - version: str, - base_url: str | URL, - _strict_response_validation: bool, - max_retries: int = DEFAULT_MAX_RETRIES, - timeout: float | Timeout | None = DEFAULT_TIMEOUT, - custom_headers: Mapping[str, str] | None = None, - custom_query: Mapping[str, object] | None = None, - ) -> None: - self._version = version - self._base_url = self._enforce_trailing_slash(URL(base_url)) - self.max_retries = max_retries - self.timeout = timeout - self._custom_headers = custom_headers or {} - self._custom_query = custom_query or {} - self._strict_response_validation = _strict_response_validation - self._idempotency_header = None - self._platform: Platform | None = None - - if max_retries is None: # pyright: ignore[reportUnnecessaryComparison] - raise TypeError( - "max_retries cannot be None. If you want to disable retries, pass `0`; if you want unlimited retries, pass `math.inf` or a very high number; if you want the default behavior, pass `metronome.DEFAULT_MAX_RETRIES`" - ) - - def _enforce_trailing_slash(self, url: URL) -> URL: - if url.raw_path.endswith(b"/"): - return url - return url.copy_with(raw_path=url.raw_path + b"/") - - def _make_status_error_from_response( - self, - response: httpx.Response, - ) -> APIStatusError: - if response.is_closed and not response.is_stream_consumed: - # We can't read the response body as it has been closed - # before it was read. This can happen if an event hook - # raises a status error. - body = None - err_msg = f"Error code: {response.status_code}" - else: - err_text = response.text.strip() - body = err_text - - try: - body = json.loads(err_text) - err_msg = f"Error code: {response.status_code} - {body}" - except Exception: - err_msg = err_text or f"Error code: {response.status_code}" - - return self._make_status_error(err_msg, body=body, response=response) - - def _make_status_error( - self, - err_msg: str, - *, - body: object, - response: httpx.Response, - ) -> _exceptions.APIStatusError: - raise NotImplementedError() - - def _build_headers(self, options: FinalRequestOptions, *, retries_taken: int = 0) -> httpx.Headers: - custom_headers = options.headers or {} - headers_dict = _merge_mappings(self.default_headers, custom_headers) - self._validate_headers(headers_dict, custom_headers) - - # headers are case-insensitive while dictionaries are not. - headers = httpx.Headers(headers_dict) - - idempotency_header = self._idempotency_header - if idempotency_header and options.idempotency_key and idempotency_header not in headers: - headers[idempotency_header] = options.idempotency_key - - # Don't set these headers if they were already set or removed by the caller. We check - # `custom_headers`, which can contain `Omit()`, instead of `headers` to account for the removal case. - lower_custom_headers = [header.lower() for header in custom_headers] - if "x-stainless-retry-count" not in lower_custom_headers: - headers["x-stainless-retry-count"] = str(retries_taken) - if "x-stainless-read-timeout" not in lower_custom_headers: - timeout = self.timeout if isinstance(options.timeout, NotGiven) else options.timeout - if isinstance(timeout, Timeout): - timeout = timeout.read - if timeout is not None: - headers["x-stainless-read-timeout"] = str(timeout) - - return headers - - def _prepare_url(self, url: str) -> URL: - """ - Merge a URL argument together with any 'base_url' on the client, - to create the URL used for the outgoing request. - """ - # Copied from httpx's `_merge_url` method. - merge_url = URL(url) - if merge_url.is_relative_url: - merge_raw_path = self.base_url.raw_path + merge_url.raw_path.lstrip(b"/") - return self.base_url.copy_with(raw_path=merge_raw_path) - - return merge_url - - def _make_sse_decoder(self) -> SSEDecoder | SSEBytesDecoder: - return SSEDecoder() - - def _build_request( - self, - options: FinalRequestOptions, - *, - retries_taken: int = 0, - ) -> httpx.Request: - if log.isEnabledFor(logging.DEBUG): - log.debug( - "Request options: %s", - model_dump( - options, - exclude_unset=True, - # Pydantic v1 can't dump every type we support in content, so we exclude it for now. - exclude={ - "content", - } - if PYDANTIC_V1 - else {}, - ), - ) - kwargs: dict[str, Any] = {} - - json_data = options.json_data - if options.extra_json is not None: - if json_data is None: - json_data = cast(Body, options.extra_json) - elif is_mapping(json_data): - json_data = _merge_mappings(json_data, options.extra_json) - else: - raise RuntimeError(f"Unexpected JSON data type, {type(json_data)}, cannot merge with `extra_body`") - - headers = self._build_headers(options, retries_taken=retries_taken) - params = _merge_mappings(self.default_query, options.params) - content_type = headers.get("Content-Type") - files = options.files - - # If the given Content-Type header is multipart/form-data then it - # has to be removed so that httpx can generate the header with - # additional information for us as it has to be in this form - # for the server to be able to correctly parse the request: - # multipart/form-data; boundary=---abc-- - if content_type is not None and content_type.startswith("multipart/form-data"): - if "boundary" not in content_type: - # only remove the header if the boundary hasn't been explicitly set - # as the caller doesn't want httpx to come up with their own boundary - headers.pop("Content-Type") - - # As we are now sending multipart/form-data instead of application/json - # we need to tell httpx to use it, https://www.python-httpx.org/advanced/clients/#multipart-file-encoding - if json_data: - if not is_dict(json_data): - raise TypeError( - f"Expected query input to be a dictionary for multipart requests but got {type(json_data)} instead." - ) - kwargs["data"] = self._serialize_multipartform(json_data) - - # httpx determines whether or not to send a "multipart/form-data" - # request based on the truthiness of the "files" argument. - # This gets around that issue by generating a dict value that - # evaluates to true. - # - # https://github.com/encode/httpx/discussions/2399#discussioncomment-3814186 - if not files: - files = cast(HttpxRequestFiles, ForceMultipartDict()) - - prepared_url = self._prepare_url(options.url) - if "_" in prepared_url.host: - # work around https://github.com/encode/httpx/discussions/2880 - kwargs["extensions"] = {"sni_hostname": prepared_url.host.replace("_", "-")} - - is_body_allowed = options.method.lower() != "get" - - if is_body_allowed: - if options.content is not None and json_data is not None: - raise TypeError("Passing both `content` and `json_data` is not supported") - if options.content is not None and files is not None: - raise TypeError("Passing both `content` and `files` is not supported") - if options.content is not None: - kwargs["content"] = options.content - elif isinstance(json_data, bytes): - kwargs["content"] = json_data - elif not files: - # Don't set content when JSON is sent as multipart/form-data, - # since httpx's content param overrides other body arguments - kwargs["content"] = openapi_dumps(json_data) if is_given(json_data) and json_data is not None else None - kwargs["files"] = files - else: - headers.pop("Content-Type", None) - kwargs.pop("data", None) - - # TODO: report this error to httpx - return self._client.build_request( # pyright: ignore[reportUnknownMemberType] - headers=headers, - timeout=self.timeout if isinstance(options.timeout, NotGiven) else options.timeout, - method=options.method, - url=prepared_url, - # the `Query` type that we use is incompatible with qs' - # `Params` type as it needs to be typed as `Mapping[str, object]` - # so that passing a `TypedDict` doesn't cause an error. - # https://github.com/microsoft/pyright/issues/3526#event-6715453066 - params=self.qs.stringify(cast(Mapping[str, Any], params)) if params else None, - **kwargs, - ) - - def _serialize_multipartform(self, data: Mapping[object, object]) -> dict[str, object]: - items = self.qs.stringify_items( - # TODO: type ignore is required as stringify_items is well typed but we can't be - # well typed without heavy validation. - data, # type: ignore - array_format="brackets", - ) - serialized: dict[str, object] = {} - for key, value in items: - existing = serialized.get(key) - - if not existing: - serialized[key] = value - continue - - # If a value has already been set for this key then that - # means we're sending data like `array[]=[1, 2, 3]` and we - # need to tell httpx that we want to send multiple values with - # the same key which is done by using a list or a tuple. - # - # Note: 2d arrays should never result in the same key at both - # levels so it's safe to assume that if the value is a list, - # it was because we changed it to be a list. - if is_list(existing): - existing.append(value) - else: - serialized[key] = [existing, value] - - return serialized - - def _maybe_override_cast_to(self, cast_to: type[ResponseT], options: FinalRequestOptions) -> type[ResponseT]: - if not is_given(options.headers): - return cast_to - - # make a copy of the headers so we don't mutate user-input - headers = dict(options.headers) - - # we internally support defining a temporary header to override the - # default `cast_to` type for use with `.with_raw_response` and `.with_streaming_response` - # see _response.py for implementation details - override_cast_to = headers.pop(OVERRIDE_CAST_TO_HEADER, not_given) - if is_given(override_cast_to): - options.headers = headers - return cast(Type[ResponseT], override_cast_to) - - return cast_to - - def _should_stream_response_body(self, request: httpx.Request) -> bool: - return request.headers.get(RAW_RESPONSE_HEADER) == "stream" # type: ignore[no-any-return] - - def _process_response_data( - self, - *, - data: object, - cast_to: type[ResponseT], - response: httpx.Response, - ) -> ResponseT: - if data is None: - return cast(ResponseT, None) - - if cast_to is object: - return cast(ResponseT, data) - - try: - if inspect.isclass(cast_to) and issubclass(cast_to, ModelBuilderProtocol): - return cast(ResponseT, cast_to.build(response=response, data=data)) - - if self._strict_response_validation: - return cast(ResponseT, validate_type(type_=cast_to, value=data)) - - return cast(ResponseT, construct_type(type_=cast_to, value=data)) - except pydantic.ValidationError as err: - raise APIResponseValidationError(response=response, body=data) from err - - @property - def qs(self) -> Querystring: - return Querystring() - - @property - def custom_auth(self) -> httpx.Auth | None: - return None - - @property - def auth_headers(self) -> dict[str, str]: - return {} - - @property - def default_headers(self) -> dict[str, str | Omit]: - return { - "Accept": "application/json", - "Content-Type": "application/json", - "User-Agent": self.user_agent, - **self.platform_headers(), - **self.auth_headers, - **self._custom_headers, - } - - @property - def default_query(self) -> dict[str, object]: - return { - **self._custom_query, - } - - def _validate_headers( - self, - headers: Headers, # noqa: ARG002 - custom_headers: Headers, # noqa: ARG002 - ) -> None: - """Validate the given default headers and custom headers. - - Does nothing by default. - """ - return - - @property - def user_agent(self) -> str: - return f"{self.__class__.__name__}/Python {self._version}" - - @property - def base_url(self) -> URL: - return self._base_url - - @base_url.setter - def base_url(self, url: URL | str) -> None: - self._base_url = self._enforce_trailing_slash(url if isinstance(url, URL) else URL(url)) - - def platform_headers(self) -> Dict[str, str]: - # the actual implementation is in a separate `lru_cache` decorated - # function because adding `lru_cache` to methods will leak memory - # https://github.com/python/cpython/issues/88476 - return platform_headers(self._version, platform=self._platform) - - def _parse_retry_after_header(self, response_headers: Optional[httpx.Headers] = None) -> float | None: - """Returns a float of the number of seconds (not milliseconds) to wait after retrying, or None if unspecified. - - About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After - See also https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After#syntax - """ - if response_headers is None: - return None - - # First, try the non-standard `retry-after-ms` header for milliseconds, - # which is more precise than integer-seconds `retry-after` - try: - retry_ms_header = response_headers.get("retry-after-ms", None) - return float(retry_ms_header) / 1000 - except (TypeError, ValueError): - pass - - # Next, try parsing `retry-after` header as seconds (allowing nonstandard floats). - retry_header = response_headers.get("retry-after") - try: - # note: the spec indicates that this should only ever be an integer - # but if someone sends a float there's no reason for us to not respect it - return float(retry_header) - except (TypeError, ValueError): - pass - - # Last, try parsing `retry-after` as a date. - retry_date_tuple = email.utils.parsedate_tz(retry_header) - if retry_date_tuple is None: - return None - - retry_date = email.utils.mktime_tz(retry_date_tuple) - return float(retry_date - time.time()) - - def _calculate_retry_timeout( - self, - remaining_retries: int, - options: FinalRequestOptions, - response_headers: Optional[httpx.Headers] = None, - ) -> float: - max_retries = options.get_max_retries(self.max_retries) - - # If the API asks us to wait a certain amount of time (and it's a reasonable amount), just do what it says. - retry_after = self._parse_retry_after_header(response_headers) - if retry_after is not None and 0 < retry_after <= 60: - return retry_after - - # Also cap retry count to 1000 to avoid any potential overflows with `pow` - nb_retries = min(max_retries - remaining_retries, 1000) - - # Apply exponential backoff, but not more than the max. - sleep_seconds = min(INITIAL_RETRY_DELAY * pow(2.0, nb_retries), MAX_RETRY_DELAY) - - # Apply some jitter, plus-or-minus half a second. - jitter = 1 - 0.25 * random() - timeout = sleep_seconds * jitter - return timeout if timeout >= 0 else 0 - - def _should_retry(self, response: httpx.Response) -> bool: - # Note: this is not a standard header - should_retry_header = response.headers.get("x-should-retry") - - # If the server explicitly says whether or not to retry, obey. - if should_retry_header == "true": - log.debug("Retrying as header `x-should-retry` is set to `true`") - return True - if should_retry_header == "false": - log.debug("Not retrying as header `x-should-retry` is set to `false`") - return False - - # Retry on request timeouts. - if response.status_code == 408: - log.debug("Retrying due to status code %i", response.status_code) - return True - - # Retry on lock timeouts. - if response.status_code == 409: - log.debug("Retrying due to status code %i", response.status_code) - return True - - # Retry on rate limits. - if response.status_code == 429: - log.debug("Retrying due to status code %i", response.status_code) - return True - - # Retry internal errors. - if response.status_code >= 500: - log.debug("Retrying due to status code %i", response.status_code) - return True - - log.debug("Not retrying") - return False - - def _idempotency_key(self) -> str: - return f"stainless-python-retry-{uuid.uuid4()}" - - -class _DefaultHttpxClient(httpx.Client): - def __init__(self, **kwargs: Any) -> None: - kwargs.setdefault("timeout", DEFAULT_TIMEOUT) - kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) - kwargs.setdefault("follow_redirects", True) - super().__init__(**kwargs) - - -if TYPE_CHECKING: - DefaultHttpxClient = httpx.Client - """An alias to `httpx.Client` that provides the same defaults that this SDK - uses internally. - - This is useful because overriding the `http_client` with your own instance of - `httpx.Client` will result in httpx's defaults being used, not ours. - """ -else: - DefaultHttpxClient = _DefaultHttpxClient - - -class SyncHttpxClientWrapper(DefaultHttpxClient): - def __del__(self) -> None: - if self.is_closed: - return - - try: - self.close() - except Exception: - pass - - -class SyncAPIClient(BaseClient[httpx.Client, Stream[Any]]): - _client: httpx.Client - _default_stream_cls: type[Stream[Any]] | None = None - - def __init__( - self, - *, - version: str, - base_url: str | URL, - max_retries: int = DEFAULT_MAX_RETRIES, - timeout: float | Timeout | None | NotGiven = not_given, - http_client: httpx.Client | None = None, - custom_headers: Mapping[str, str] | None = None, - custom_query: Mapping[str, object] | None = None, - _strict_response_validation: bool, - ) -> None: - if not is_given(timeout): - # if the user passed in a custom http client with a non-default - # timeout set then we use that timeout. - # - # note: there is an edge case here where the user passes in a client - # where they've explicitly set the timeout to match the default timeout - # as this check is structural, meaning that we'll think they didn't - # pass in a timeout and will ignore it - if http_client and http_client.timeout != HTTPX_DEFAULT_TIMEOUT: - timeout = http_client.timeout - else: - timeout = DEFAULT_TIMEOUT - - if http_client is not None and not isinstance(http_client, httpx.Client): # pyright: ignore[reportUnnecessaryIsInstance] - raise TypeError( - f"Invalid `http_client` argument; Expected an instance of `httpx.Client` but got {type(http_client)}" - ) - - super().__init__( - version=version, - # cast to a valid type because mypy doesn't understand our type narrowing - timeout=cast(Timeout, timeout), - base_url=base_url, - max_retries=max_retries, - custom_query=custom_query, - custom_headers=custom_headers, - _strict_response_validation=_strict_response_validation, - ) - self._client = http_client or SyncHttpxClientWrapper( - base_url=base_url, - # cast to a valid type because mypy doesn't understand our type narrowing - timeout=cast(Timeout, timeout), - ) - - def is_closed(self) -> bool: - return self._client.is_closed - - def close(self) -> None: - """Close the underlying HTTPX client. - - The client will *not* be usable after this. - """ - # If an error is thrown while constructing a client, self._client - # may not be present - if hasattr(self, "_client"): - self._client.close() - - def __enter__(self: _T) -> _T: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.close() - - def _prepare_options( - self, - options: FinalRequestOptions, # noqa: ARG002 - ) -> FinalRequestOptions: - """Hook for mutating the given options""" - return options - - def _prepare_request( - self, - request: httpx.Request, # noqa: ARG002 - ) -> None: - """This method is used as a callback for mutating the `Request` object - after it has been constructed. - This is useful for cases where you want to add certain headers based off of - the request properties, e.g. `url`, `method` etc. - """ - return None - - @overload - def request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: Literal[True], - stream_cls: Type[_StreamT], - ) -> _StreamT: ... - - @overload - def request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: Literal[False] = False, - ) -> ResponseT: ... - - @overload - def request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: bool = False, - stream_cls: Type[_StreamT] | None = None, - ) -> ResponseT | _StreamT: ... - - def request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: bool = False, - stream_cls: type[_StreamT] | None = None, - ) -> ResponseT | _StreamT: - cast_to = self._maybe_override_cast_to(cast_to, options) - - # create a copy of the options we were given so that if the - # options are mutated later & we then retry, the retries are - # given the original options - input_options = model_copy(options) - if input_options.idempotency_key is None and input_options.method.lower() != "get": - # ensure the idempotency key is reused between requests - input_options.idempotency_key = self._idempotency_key() - - response: httpx.Response | None = None - max_retries = input_options.get_max_retries(self.max_retries) - - retries_taken = 0 - for retries_taken in range(max_retries + 1): - options = model_copy(input_options) - options = self._prepare_options(options) - - remaining_retries = max_retries - retries_taken - request = self._build_request(options, retries_taken=retries_taken) - self._prepare_request(request) - - kwargs: HttpxSendArgs = {} - if self.custom_auth is not None: - kwargs["auth"] = self.custom_auth - - if options.follow_redirects is not None: - kwargs["follow_redirects"] = options.follow_redirects - - log.debug("Sending HTTP Request: %s %s", request.method, request.url) - - response = None - try: - response = self._client.send( - request, - stream=stream or self._should_stream_response_body(request=request), - **kwargs, - ) - except httpx.TimeoutException as err: - log.debug("Encountered httpx.TimeoutException", exc_info=True) - - if remaining_retries > 0: - self._sleep_for_retry( - retries_taken=retries_taken, - max_retries=max_retries, - options=input_options, - response=None, - ) - continue - - log.debug("Raising timeout error") - raise APITimeoutError(request=request) from err - except Exception as err: - log.debug("Encountered Exception", exc_info=True) - - if remaining_retries > 0: - self._sleep_for_retry( - retries_taken=retries_taken, - max_retries=max_retries, - options=input_options, - response=None, - ) - continue - - log.debug("Raising connection error") - raise APIConnectionError(request=request) from err - - log.debug( - 'HTTP Response: %s %s "%i %s" %s', - request.method, - request.url, - response.status_code, - response.reason_phrase, - response.headers, - ) - - try: - response.raise_for_status() - except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code - log.debug("Encountered httpx.HTTPStatusError", exc_info=True) - - if remaining_retries > 0 and self._should_retry(err.response): - err.response.close() - self._sleep_for_retry( - retries_taken=retries_taken, - max_retries=max_retries, - options=input_options, - response=response, - ) - continue - - # If the response is streamed then we need to explicitly read the response - # to completion before attempting to access the response text. - if not err.response.is_closed: - err.response.read() - - log.debug("Re-raising status error") - raise self._make_status_error_from_response(err.response) from None - - break - - assert response is not None, "could not resolve response (should never happen)" - return self._process_response( - cast_to=cast_to, - options=options, - response=response, - stream=stream, - stream_cls=stream_cls, - retries_taken=retries_taken, - ) - - def _sleep_for_retry( - self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx.Response | None - ) -> None: - remaining_retries = max_retries - retries_taken - if remaining_retries == 1: - log.debug("1 retry left") - else: - log.debug("%i retries left", remaining_retries) - - timeout = self._calculate_retry_timeout(remaining_retries, options, response.headers if response else None) - log.info("Retrying request to %s in %f seconds", options.url, timeout) - - time.sleep(timeout) - - def _process_response( - self, - *, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - response: httpx.Response, - stream: bool, - stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, - retries_taken: int = 0, - ) -> ResponseT: - origin = get_origin(cast_to) or cast_to - - if ( - inspect.isclass(origin) - and issubclass(origin, BaseAPIResponse) - # we only want to actually return the custom BaseAPIResponse class if we're - # returning the raw response, or if we're not streaming SSE, as if we're streaming - # SSE then `cast_to` doesn't actively reflect the type we need to parse into - and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER))) - ): - if not issubclass(origin, APIResponse): - raise TypeError(f"API Response types must subclass {APIResponse}; Received {origin}") - - response_cls = cast("type[BaseAPIResponse[Any]]", cast_to) - return cast( - ResponseT, - response_cls( - raw=response, - client=self, - cast_to=extract_response_type(response_cls), - stream=stream, - stream_cls=stream_cls, - options=options, - retries_taken=retries_taken, - ), - ) - - if cast_to == httpx.Response: - return cast(ResponseT, response) - - api_response = APIResponse( - raw=response, - client=self, - cast_to=cast("type[ResponseT]", cast_to), # pyright: ignore[reportUnnecessaryCast] - stream=stream, - stream_cls=stream_cls, - options=options, - retries_taken=retries_taken, - ) - if bool(response.request.headers.get(RAW_RESPONSE_HEADER)): - return cast(ResponseT, api_response) - - return api_response.parse() - - def _request_api_list( - self, - model: Type[object], - page: Type[SyncPageT], - options: FinalRequestOptions, - ) -> SyncPageT: - def _parser(resp: SyncPageT) -> SyncPageT: - resp._set_private_attributes( - client=self, - model=model, - options=options, - ) - return resp - - options.post_parser = _parser - - return self.request(page, options, stream=False) - - @overload - def get( - self, - path: str, - *, - cast_to: Type[ResponseT], - options: RequestOptions = {}, - stream: Literal[False] = False, - ) -> ResponseT: ... - - @overload - def get( - self, - path: str, - *, - cast_to: Type[ResponseT], - options: RequestOptions = {}, - stream: Literal[True], - stream_cls: type[_StreamT], - ) -> _StreamT: ... - - @overload - def get( - self, - path: str, - *, - cast_to: Type[ResponseT], - options: RequestOptions = {}, - stream: bool, - stream_cls: type[_StreamT] | None = None, - ) -> ResponseT | _StreamT: ... - - def get( - self, - path: str, - *, - cast_to: Type[ResponseT], - options: RequestOptions = {}, - stream: bool = False, - stream_cls: type[_StreamT] | None = None, - ) -> ResponseT | _StreamT: - opts = FinalRequestOptions.construct(method="get", url=path, **options) - # cast is required because mypy complains about returning Any even though - # it understands the type variables - return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) - - @overload - def post( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: BinaryTypes | None = None, - options: RequestOptions = {}, - files: RequestFiles | None = None, - stream: Literal[False] = False, - ) -> ResponseT: ... - - @overload - def post( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: BinaryTypes | None = None, - options: RequestOptions = {}, - files: RequestFiles | None = None, - stream: Literal[True], - stream_cls: type[_StreamT], - ) -> _StreamT: ... - - @overload - def post( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: BinaryTypes | None = None, - options: RequestOptions = {}, - files: RequestFiles | None = None, - stream: bool, - stream_cls: type[_StreamT] | None = None, - ) -> ResponseT | _StreamT: ... - - def post( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: BinaryTypes | None = None, - options: RequestOptions = {}, - files: RequestFiles | None = None, - stream: bool = False, - stream_cls: type[_StreamT] | None = None, - ) -> ResponseT | _StreamT: - if body is not None and content is not None: - raise TypeError("Passing both `body` and `content` is not supported") - if files is not None and content is not None: - raise TypeError("Passing both `files` and `content` is not supported") - if isinstance(body, bytes): - warnings.warn( - "Passing raw bytes as `body` is deprecated and will be removed in a future version. " - "Please pass raw bytes via the `content` parameter instead.", - DeprecationWarning, - stacklevel=2, - ) - opts = FinalRequestOptions.construct( - method="post", url=path, json_data=body, content=content, files=to_httpx_files(files), **options - ) - return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls)) - - def patch( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: BinaryTypes | None = None, - files: RequestFiles | None = None, - options: RequestOptions = {}, - ) -> ResponseT: - if body is not None and content is not None: - raise TypeError("Passing both `body` and `content` is not supported") - if files is not None and content is not None: - raise TypeError("Passing both `files` and `content` is not supported") - if isinstance(body, bytes): - warnings.warn( - "Passing raw bytes as `body` is deprecated and will be removed in a future version. " - "Please pass raw bytes via the `content` parameter instead.", - DeprecationWarning, - stacklevel=2, - ) - opts = FinalRequestOptions.construct( - method="patch", url=path, json_data=body, content=content, files=to_httpx_files(files), **options - ) - return self.request(cast_to, opts) - - def put( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: BinaryTypes | None = None, - files: RequestFiles | None = None, - options: RequestOptions = {}, - ) -> ResponseT: - if body is not None and content is not None: - raise TypeError("Passing both `body` and `content` is not supported") - if files is not None and content is not None: - raise TypeError("Passing both `files` and `content` is not supported") - if isinstance(body, bytes): - warnings.warn( - "Passing raw bytes as `body` is deprecated and will be removed in a future version. " - "Please pass raw bytes via the `content` parameter instead.", - DeprecationWarning, - stacklevel=2, - ) - opts = FinalRequestOptions.construct( - method="put", url=path, json_data=body, content=content, files=to_httpx_files(files), **options - ) - return self.request(cast_to, opts) - - def delete( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: BinaryTypes | None = None, - options: RequestOptions = {}, - ) -> ResponseT: - if body is not None and content is not None: - raise TypeError("Passing both `body` and `content` is not supported") - if isinstance(body, bytes): - warnings.warn( - "Passing raw bytes as `body` is deprecated and will be removed in a future version. " - "Please pass raw bytes via the `content` parameter instead.", - DeprecationWarning, - stacklevel=2, - ) - opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options) - return self.request(cast_to, opts) - - def get_api_list( - self, - path: str, - *, - model: Type[object], - page: Type[SyncPageT], - body: Body | None = None, - options: RequestOptions = {}, - method: str = "get", - ) -> SyncPageT: - opts = FinalRequestOptions.construct(method=method, url=path, json_data=body, **options) - return self._request_api_list(model, page, opts) - - -class _DefaultAsyncHttpxClient(httpx.AsyncClient): - def __init__(self, **kwargs: Any) -> None: - kwargs.setdefault("timeout", DEFAULT_TIMEOUT) - kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) - kwargs.setdefault("follow_redirects", True) - super().__init__(**kwargs) - - -try: - import httpx_aiohttp -except ImportError: - - class _DefaultAioHttpClient(httpx.AsyncClient): - def __init__(self, **_kwargs: Any) -> None: - raise RuntimeError("To use the aiohttp client you must have installed the package with the `aiohttp` extra") -else: - - class _DefaultAioHttpClient(httpx_aiohttp.HttpxAiohttpClient): # type: ignore - def __init__(self, **kwargs: Any) -> None: - kwargs.setdefault("timeout", DEFAULT_TIMEOUT) - kwargs.setdefault("limits", DEFAULT_CONNECTION_LIMITS) - kwargs.setdefault("follow_redirects", True) - - super().__init__(**kwargs) - - -if TYPE_CHECKING: - DefaultAsyncHttpxClient = httpx.AsyncClient - """An alias to `httpx.AsyncClient` that provides the same defaults that this SDK - uses internally. - - This is useful because overriding the `http_client` with your own instance of - `httpx.AsyncClient` will result in httpx's defaults being used, not ours. - """ - - DefaultAioHttpClient = httpx.AsyncClient - """An alias to `httpx.AsyncClient` that changes the default HTTP transport to `aiohttp`.""" -else: - DefaultAsyncHttpxClient = _DefaultAsyncHttpxClient - DefaultAioHttpClient = _DefaultAioHttpClient - - -class AsyncHttpxClientWrapper(DefaultAsyncHttpxClient): - def __del__(self) -> None: - if self.is_closed: - return - - try: - # TODO(someday): support non asyncio runtimes here - asyncio.get_running_loop().create_task(self.aclose()) - except Exception: - pass - - -class AsyncAPIClient(BaseClient[httpx.AsyncClient, AsyncStream[Any]]): - _client: httpx.AsyncClient - _default_stream_cls: type[AsyncStream[Any]] | None = None - - def __init__( - self, - *, - version: str, - base_url: str | URL, - _strict_response_validation: bool, - max_retries: int = DEFAULT_MAX_RETRIES, - timeout: float | Timeout | None | NotGiven = not_given, - http_client: httpx.AsyncClient | None = None, - custom_headers: Mapping[str, str] | None = None, - custom_query: Mapping[str, object] | None = None, - ) -> None: - if not is_given(timeout): - # if the user passed in a custom http client with a non-default - # timeout set then we use that timeout. - # - # note: there is an edge case here where the user passes in a client - # where they've explicitly set the timeout to match the default timeout - # as this check is structural, meaning that we'll think they didn't - # pass in a timeout and will ignore it - if http_client and http_client.timeout != HTTPX_DEFAULT_TIMEOUT: - timeout = http_client.timeout - else: - timeout = DEFAULT_TIMEOUT - - if http_client is not None and not isinstance(http_client, httpx.AsyncClient): # pyright: ignore[reportUnnecessaryIsInstance] - raise TypeError( - f"Invalid `http_client` argument; Expected an instance of `httpx.AsyncClient` but got {type(http_client)}" - ) - - super().__init__( - version=version, - base_url=base_url, - # cast to a valid type because mypy doesn't understand our type narrowing - timeout=cast(Timeout, timeout), - max_retries=max_retries, - custom_query=custom_query, - custom_headers=custom_headers, - _strict_response_validation=_strict_response_validation, - ) - self._client = http_client or AsyncHttpxClientWrapper( - base_url=base_url, - # cast to a valid type because mypy doesn't understand our type narrowing - timeout=cast(Timeout, timeout), - ) - - def is_closed(self) -> bool: - return self._client.is_closed - - async def close(self) -> None: - """Close the underlying HTTPX client. - - The client will *not* be usable after this. - """ - await self._client.aclose() - - async def __aenter__(self: _T) -> _T: - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - await self.close() - - async def _prepare_options( - self, - options: FinalRequestOptions, # noqa: ARG002 - ) -> FinalRequestOptions: - """Hook for mutating the given options""" - return options - - async def _prepare_request( - self, - request: httpx.Request, # noqa: ARG002 - ) -> None: - """This method is used as a callback for mutating the `Request` object - after it has been constructed. - This is useful for cases where you want to add certain headers based off of - the request properties, e.g. `url`, `method` etc. - """ - return None - - @overload - async def request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: Literal[False] = False, - ) -> ResponseT: ... - - @overload - async def request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: Literal[True], - stream_cls: type[_AsyncStreamT], - ) -> _AsyncStreamT: ... - - @overload - async def request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: bool, - stream_cls: type[_AsyncStreamT] | None = None, - ) -> ResponseT | _AsyncStreamT: ... - - async def request( - self, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - *, - stream: bool = False, - stream_cls: type[_AsyncStreamT] | None = None, - ) -> ResponseT | _AsyncStreamT: - if self._platform is None: - # `get_platform` can make blocking IO calls so we - # execute it earlier while we are in an async context - self._platform = await asyncify(get_platform)() - - cast_to = self._maybe_override_cast_to(cast_to, options) - - # create a copy of the options we were given so that if the - # options are mutated later & we then retry, the retries are - # given the original options - input_options = model_copy(options) - if input_options.idempotency_key is None and input_options.method.lower() != "get": - # ensure the idempotency key is reused between requests - input_options.idempotency_key = self._idempotency_key() - - response: httpx.Response | None = None - max_retries = input_options.get_max_retries(self.max_retries) - - retries_taken = 0 - for retries_taken in range(max_retries + 1): - options = model_copy(input_options) - options = await self._prepare_options(options) - - remaining_retries = max_retries - retries_taken - request = self._build_request(options, retries_taken=retries_taken) - await self._prepare_request(request) - - kwargs: HttpxSendArgs = {} - if self.custom_auth is not None: - kwargs["auth"] = self.custom_auth - - if options.follow_redirects is not None: - kwargs["follow_redirects"] = options.follow_redirects - - log.debug("Sending HTTP Request: %s %s", request.method, request.url) - - response = None - try: - response = await self._client.send( - request, - stream=stream or self._should_stream_response_body(request=request), - **kwargs, - ) - except httpx.TimeoutException as err: - log.debug("Encountered httpx.TimeoutException", exc_info=True) - - if remaining_retries > 0: - await self._sleep_for_retry( - retries_taken=retries_taken, - max_retries=max_retries, - options=input_options, - response=None, - ) - continue - - log.debug("Raising timeout error") - raise APITimeoutError(request=request) from err - except Exception as err: - log.debug("Encountered Exception", exc_info=True) - - if remaining_retries > 0: - await self._sleep_for_retry( - retries_taken=retries_taken, - max_retries=max_retries, - options=input_options, - response=None, - ) - continue - - log.debug("Raising connection error") - raise APIConnectionError(request=request) from err - - log.debug( - 'HTTP Response: %s %s "%i %s" %s', - request.method, - request.url, - response.status_code, - response.reason_phrase, - response.headers, - ) - - try: - response.raise_for_status() - except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code - log.debug("Encountered httpx.HTTPStatusError", exc_info=True) - - if remaining_retries > 0 and self._should_retry(err.response): - await err.response.aclose() - await self._sleep_for_retry( - retries_taken=retries_taken, - max_retries=max_retries, - options=input_options, - response=response, - ) - continue - - # If the response is streamed then we need to explicitly read the response - # to completion before attempting to access the response text. - if not err.response.is_closed: - await err.response.aread() - - log.debug("Re-raising status error") - raise self._make_status_error_from_response(err.response) from None - - break - - assert response is not None, "could not resolve response (should never happen)" - return await self._process_response( - cast_to=cast_to, - options=options, - response=response, - stream=stream, - stream_cls=stream_cls, - retries_taken=retries_taken, - ) - - async def _sleep_for_retry( - self, *, retries_taken: int, max_retries: int, options: FinalRequestOptions, response: httpx.Response | None - ) -> None: - remaining_retries = max_retries - retries_taken - if remaining_retries == 1: - log.debug("1 retry left") - else: - log.debug("%i retries left", remaining_retries) - - timeout = self._calculate_retry_timeout(remaining_retries, options, response.headers if response else None) - log.info("Retrying request to %s in %f seconds", options.url, timeout) - - await anyio.sleep(timeout) - - async def _process_response( - self, - *, - cast_to: Type[ResponseT], - options: FinalRequestOptions, - response: httpx.Response, - stream: bool, - stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, - retries_taken: int = 0, - ) -> ResponseT: - origin = get_origin(cast_to) or cast_to - - if ( - inspect.isclass(origin) - and issubclass(origin, BaseAPIResponse) - # we only want to actually return the custom BaseAPIResponse class if we're - # returning the raw response, or if we're not streaming SSE, as if we're streaming - # SSE then `cast_to` doesn't actively reflect the type we need to parse into - and (not stream or bool(response.request.headers.get(RAW_RESPONSE_HEADER))) - ): - if not issubclass(origin, AsyncAPIResponse): - raise TypeError(f"API Response types must subclass {AsyncAPIResponse}; Received {origin}") - - response_cls = cast("type[BaseAPIResponse[Any]]", cast_to) - return cast( - "ResponseT", - response_cls( - raw=response, - client=self, - cast_to=extract_response_type(response_cls), - stream=stream, - stream_cls=stream_cls, - options=options, - retries_taken=retries_taken, - ), - ) - - if cast_to == httpx.Response: - return cast(ResponseT, response) - - api_response = AsyncAPIResponse( - raw=response, - client=self, - cast_to=cast("type[ResponseT]", cast_to), # pyright: ignore[reportUnnecessaryCast] - stream=stream, - stream_cls=stream_cls, - options=options, - retries_taken=retries_taken, - ) - if bool(response.request.headers.get(RAW_RESPONSE_HEADER)): - return cast(ResponseT, api_response) - - return await api_response.parse() - - def _request_api_list( - self, - model: Type[_T], - page: Type[AsyncPageT], - options: FinalRequestOptions, - ) -> AsyncPaginator[_T, AsyncPageT]: - return AsyncPaginator(client=self, options=options, page_cls=page, model=model) - - @overload - async def get( - self, - path: str, - *, - cast_to: Type[ResponseT], - options: RequestOptions = {}, - stream: Literal[False] = False, - ) -> ResponseT: ... - - @overload - async def get( - self, - path: str, - *, - cast_to: Type[ResponseT], - options: RequestOptions = {}, - stream: Literal[True], - stream_cls: type[_AsyncStreamT], - ) -> _AsyncStreamT: ... - - @overload - async def get( - self, - path: str, - *, - cast_to: Type[ResponseT], - options: RequestOptions = {}, - stream: bool, - stream_cls: type[_AsyncStreamT] | None = None, - ) -> ResponseT | _AsyncStreamT: ... - - async def get( - self, - path: str, - *, - cast_to: Type[ResponseT], - options: RequestOptions = {}, - stream: bool = False, - stream_cls: type[_AsyncStreamT] | None = None, - ) -> ResponseT | _AsyncStreamT: - opts = FinalRequestOptions.construct(method="get", url=path, **options) - return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) - - @overload - async def post( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: AsyncBinaryTypes | None = None, - files: RequestFiles | None = None, - options: RequestOptions = {}, - stream: Literal[False] = False, - ) -> ResponseT: ... - - @overload - async def post( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: AsyncBinaryTypes | None = None, - files: RequestFiles | None = None, - options: RequestOptions = {}, - stream: Literal[True], - stream_cls: type[_AsyncStreamT], - ) -> _AsyncStreamT: ... - - @overload - async def post( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: AsyncBinaryTypes | None = None, - files: RequestFiles | None = None, - options: RequestOptions = {}, - stream: bool, - stream_cls: type[_AsyncStreamT] | None = None, - ) -> ResponseT | _AsyncStreamT: ... - - async def post( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: AsyncBinaryTypes | None = None, - files: RequestFiles | None = None, - options: RequestOptions = {}, - stream: bool = False, - stream_cls: type[_AsyncStreamT] | None = None, - ) -> ResponseT | _AsyncStreamT: - if body is not None and content is not None: - raise TypeError("Passing both `body` and `content` is not supported") - if files is not None and content is not None: - raise TypeError("Passing both `files` and `content` is not supported") - if isinstance(body, bytes): - warnings.warn( - "Passing raw bytes as `body` is deprecated and will be removed in a future version. " - "Please pass raw bytes via the `content` parameter instead.", - DeprecationWarning, - stacklevel=2, - ) - opts = FinalRequestOptions.construct( - method="post", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options - ) - return await self.request(cast_to, opts, stream=stream, stream_cls=stream_cls) - - async def patch( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: AsyncBinaryTypes | None = None, - files: RequestFiles | None = None, - options: RequestOptions = {}, - ) -> ResponseT: - if body is not None and content is not None: - raise TypeError("Passing both `body` and `content` is not supported") - if files is not None and content is not None: - raise TypeError("Passing both `files` and `content` is not supported") - if isinstance(body, bytes): - warnings.warn( - "Passing raw bytes as `body` is deprecated and will be removed in a future version. " - "Please pass raw bytes via the `content` parameter instead.", - DeprecationWarning, - stacklevel=2, - ) - opts = FinalRequestOptions.construct( - method="patch", - url=path, - json_data=body, - content=content, - files=await async_to_httpx_files(files), - **options, - ) - return await self.request(cast_to, opts) - - async def put( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: AsyncBinaryTypes | None = None, - files: RequestFiles | None = None, - options: RequestOptions = {}, - ) -> ResponseT: - if body is not None and content is not None: - raise TypeError("Passing both `body` and `content` is not supported") - if files is not None and content is not None: - raise TypeError("Passing both `files` and `content` is not supported") - if isinstance(body, bytes): - warnings.warn( - "Passing raw bytes as `body` is deprecated and will be removed in a future version. " - "Please pass raw bytes via the `content` parameter instead.", - DeprecationWarning, - stacklevel=2, - ) - opts = FinalRequestOptions.construct( - method="put", url=path, json_data=body, content=content, files=await async_to_httpx_files(files), **options - ) - return await self.request(cast_to, opts) - - async def delete( - self, - path: str, - *, - cast_to: Type[ResponseT], - body: Body | None = None, - content: AsyncBinaryTypes | None = None, - options: RequestOptions = {}, - ) -> ResponseT: - if body is not None and content is not None: - raise TypeError("Passing both `body` and `content` is not supported") - if isinstance(body, bytes): - warnings.warn( - "Passing raw bytes as `body` is deprecated and will be removed in a future version. " - "Please pass raw bytes via the `content` parameter instead.", - DeprecationWarning, - stacklevel=2, - ) - opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, content=content, **options) - return await self.request(cast_to, opts) - - def get_api_list( - self, - path: str, - *, - model: Type[_T], - page: Type[AsyncPageT], - body: Body | None = None, - options: RequestOptions = {}, - method: str = "get", - ) -> AsyncPaginator[_T, AsyncPageT]: - opts = FinalRequestOptions.construct(method=method, url=path, json_data=body, **options) - return self._request_api_list(model, page, opts) - - -def make_request_options( - *, - query: Query | None = None, - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - idempotency_key: str | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - post_parser: PostParser | NotGiven = not_given, -) -> RequestOptions: - """Create a dict of type RequestOptions without keys of NotGiven values.""" - options: RequestOptions = {} - if extra_headers is not None: - options["headers"] = extra_headers - - if extra_body is not None: - options["extra_json"] = cast(AnyMapping, extra_body) - - if query is not None: - options["params"] = query - - if extra_query is not None: - options["params"] = {**options.get("params", {}), **extra_query} - - if not isinstance(timeout, NotGiven): - options["timeout"] = timeout - - if idempotency_key is not None: - options["idempotency_key"] = idempotency_key - - if is_given(post_parser): - # internal - options["post_parser"] = post_parser # type: ignore - - return options - - -class ForceMultipartDict(Dict[str, None]): - def __bool__(self) -> bool: - return True - - -class OtherPlatform: - def __init__(self, name: str) -> None: - self.name = name - - @override - def __str__(self) -> str: - return f"Other:{self.name}" - - -Platform = Union[ - OtherPlatform, - Literal[ - "MacOS", - "Linux", - "Windows", - "FreeBSD", - "OpenBSD", - "iOS", - "Android", - "Unknown", - ], -] - - -def get_platform() -> Platform: - try: - system = platform.system().lower() - platform_name = platform.platform().lower() - except Exception: - return "Unknown" - - if "iphone" in platform_name or "ipad" in platform_name: - # Tested using Python3IDE on an iPhone 11 and Pythonista on an iPad 7 - # system is Darwin and platform_name is a string like: - # - Darwin-21.6.0-iPhone12,1-64bit - # - Darwin-21.6.0-iPad7,11-64bit - return "iOS" - - if system == "darwin": - return "MacOS" - - if system == "windows": - return "Windows" - - if "android" in platform_name: - # Tested using Pydroid 3 - # system is Linux and platform_name is a string like 'Linux-5.10.81-android12-9-00001-geba40aecb3b7-ab8534902-aarch64-with-libc' - return "Android" - - if system == "linux": - # https://distro.readthedocs.io/en/latest/#distro.id - distro_id = distro.id() - if distro_id == "freebsd": - return "FreeBSD" - - if distro_id == "openbsd": - return "OpenBSD" - - return "Linux" - - if platform_name: - return OtherPlatform(platform_name) - - return "Unknown" - - -@lru_cache(maxsize=None) -def platform_headers(version: str, *, platform: Platform | None) -> Dict[str, str]: - return { - "X-Stainless-Lang": "python", - "X-Stainless-Package-Version": version, - "X-Stainless-OS": str(platform or get_platform()), - "X-Stainless-Arch": str(get_architecture()), - "X-Stainless-Runtime": get_python_runtime(), - "X-Stainless-Runtime-Version": get_python_version(), - } - - -class OtherArch: - def __init__(self, name: str) -> None: - self.name = name - - @override - def __str__(self) -> str: - return f"other:{self.name}" - - -Arch = Union[OtherArch, Literal["x32", "x64", "arm", "arm64", "unknown"]] - - -def get_python_runtime() -> str: - try: - return platform.python_implementation() - except Exception: - return "unknown" - - -def get_python_version() -> str: - try: - return platform.python_version() - except Exception: - return "unknown" - - -def get_architecture() -> Arch: - try: - machine = platform.machine().lower() - except Exception: - return "unknown" - - if machine in ("arm64", "aarch64"): - return "arm64" - - # TODO: untested - if machine == "arm": - return "arm" - - if machine == "x86_64": - return "x64" - - # TODO: untested - if sys.maxsize <= 2**32: - return "x32" - - if machine: - return OtherArch(machine) - - return "unknown" - - -def _merge_mappings( - obj1: Mapping[_T_co, Union[_T, Omit]], - obj2: Mapping[_T_co, Union[_T, Omit]], -) -> Dict[_T_co, _T]: - """Merge two mappings of the same type, removing any values that are instances of `Omit`. - - In cases with duplicate keys the second mapping takes precedence. - """ - merged = {**obj1, **obj2} - return {key: value for key, value in merged.items() if not isinstance(value, Omit)} diff --git a/src/metronome/_client.py b/src/metronome/_client.py deleted file mode 100644 index d9b7d4f68..000000000 --- a/src/metronome/_client.py +++ /dev/null @@ -1,508 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import os -from typing import TYPE_CHECKING, Any, Mapping -from typing_extensions import Self, override - -import httpx - -from . import _exceptions -from ._qs import Querystring -from ._types import ( - Omit, - Timeout, - NotGiven, - Transport, - ProxiesTypes, - RequestOptions, - not_given, -) -from ._utils import is_given, get_async_library -from ._compat import cached_property -from ._version import __version__ -from ._streaming import Stream as Stream, AsyncStream as AsyncStream -from ._exceptions import APIStatusError, MetronomeError -from ._base_client import ( - DEFAULT_MAX_RETRIES, - SyncAPIClient, - AsyncAPIClient, -) - -if TYPE_CHECKING: - from .resources import v1, v2 - from .resources.v1.v1 import V1Resource, AsyncV1Resource - from .resources.v2.v2 import V2Resource, AsyncV2Resource - -__all__ = [ - "Timeout", - "Transport", - "ProxiesTypes", - "RequestOptions", - "Metronome", - "AsyncMetronome", - "Client", - "AsyncClient", -] - - -class Metronome(SyncAPIClient): - # client options - bearer_token: str - webhook_secret: str | None - - def __init__( - self, - *, - bearer_token: str | None = None, - webhook_secret: str | None = None, - base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = not_given, - max_retries: int = DEFAULT_MAX_RETRIES, - default_headers: Mapping[str, str] | None = None, - default_query: Mapping[str, object] | None = None, - # Configure a custom httpx client. - # We provide a `DefaultHttpxClient` class that you can pass to retain the default values we use for `limits`, `timeout` & `follow_redirects`. - # See the [httpx documentation](https://www.python-httpx.org/api/#client) for more details. - http_client: httpx.Client | None = None, - # Enable or disable schema validation for data returned by the API. - # When enabled an error APIResponseValidationError is raised - # if the API responds with invalid data for the expected schema. - # - # This parameter may be removed or changed in the future. - # If you rely on this feature, please open a GitHub issue - # outlining your use-case to help us decide if it should be - # part of our public interface in the future. - _strict_response_validation: bool = False, - ) -> None: - """Construct a new synchronous Metronome client instance. - - This automatically infers the following arguments from their corresponding environment variables if they are not provided: - - `bearer_token` from `METRONOME_BEARER_TOKEN` - - `webhook_secret` from `METRONOME_WEBHOOK_SECRET` - """ - if bearer_token is None: - bearer_token = os.environ.get("METRONOME_BEARER_TOKEN") - if bearer_token is None: - raise MetronomeError( - "The bearer_token client option must be set either by passing bearer_token to the client or by setting the METRONOME_BEARER_TOKEN environment variable" - ) - self.bearer_token = bearer_token - - if webhook_secret is None: - webhook_secret = os.environ.get("METRONOME_WEBHOOK_SECRET") - self.webhook_secret = webhook_secret - - if base_url is None: - base_url = os.environ.get("METRONOME_BASE_URL") - if base_url is None: - base_url = f"https://api.metronome.com" - - super().__init__( - version=__version__, - base_url=base_url, - max_retries=max_retries, - timeout=timeout, - http_client=http_client, - custom_headers=default_headers, - custom_query=default_query, - _strict_response_validation=_strict_response_validation, - ) - - @cached_property - def v2(self) -> V2Resource: - from .resources.v2 import V2Resource - - return V2Resource(self) - - @cached_property - def v1(self) -> V1Resource: - from .resources.v1 import V1Resource - - return V1Resource(self) - - @cached_property - def with_raw_response(self) -> MetronomeWithRawResponse: - return MetronomeWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> MetronomeWithStreamedResponse: - return MetronomeWithStreamedResponse(self) - - @property - @override - def qs(self) -> Querystring: - return Querystring(array_format="comma") - - @property - @override - def auth_headers(self) -> dict[str, str]: - bearer_token = self.bearer_token - return {"Authorization": f"Bearer {bearer_token}"} - - @property - @override - def default_headers(self) -> dict[str, str | Omit]: - return { - **super().default_headers, - "X-Stainless-Async": "false", - **self._custom_headers, - } - - def copy( - self, - *, - bearer_token: str | None = None, - webhook_secret: str | None = None, - base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = not_given, - http_client: httpx.Client | None = None, - max_retries: int | NotGiven = not_given, - default_headers: Mapping[str, str] | None = None, - set_default_headers: Mapping[str, str] | None = None, - default_query: Mapping[str, object] | None = None, - set_default_query: Mapping[str, object] | None = None, - _extra_kwargs: Mapping[str, Any] = {}, - ) -> Self: - """ - Create a new client instance re-using the same options given to the current client with optional overriding. - """ - if default_headers is not None and set_default_headers is not None: - raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive") - - if default_query is not None and set_default_query is not None: - raise ValueError("The `default_query` and `set_default_query` arguments are mutually exclusive") - - headers = self._custom_headers - if default_headers is not None: - headers = {**headers, **default_headers} - elif set_default_headers is not None: - headers = set_default_headers - - params = self._custom_query - if default_query is not None: - params = {**params, **default_query} - elif set_default_query is not None: - params = set_default_query - - http_client = http_client or self._client - return self.__class__( - bearer_token=bearer_token or self.bearer_token, - webhook_secret=webhook_secret or self.webhook_secret, - base_url=base_url or self.base_url, - timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, - http_client=http_client, - max_retries=max_retries if is_given(max_retries) else self.max_retries, - default_headers=headers, - default_query=params, - **_extra_kwargs, - ) - - # Alias for `copy` for nicer inline usage, e.g. - # client.with_options(timeout=10).foo.create(...) - with_options = copy - - @override - def _make_status_error( - self, - err_msg: str, - *, - body: object, - response: httpx.Response, - ) -> APIStatusError: - if response.status_code == 400: - return _exceptions.BadRequestError(err_msg, response=response, body=body) - - if response.status_code == 401: - return _exceptions.AuthenticationError(err_msg, response=response, body=body) - - if response.status_code == 403: - return _exceptions.PermissionDeniedError(err_msg, response=response, body=body) - - if response.status_code == 404: - return _exceptions.NotFoundError(err_msg, response=response, body=body) - - if response.status_code == 409: - return _exceptions.ConflictError(err_msg, response=response, body=body) - - if response.status_code == 422: - return _exceptions.UnprocessableEntityError(err_msg, response=response, body=body) - - if response.status_code == 429: - return _exceptions.RateLimitError(err_msg, response=response, body=body) - - if response.status_code >= 500: - return _exceptions.InternalServerError(err_msg, response=response, body=body) - return APIStatusError(err_msg, response=response, body=body) - - -class AsyncMetronome(AsyncAPIClient): - # client options - bearer_token: str - webhook_secret: str | None - - def __init__( - self, - *, - bearer_token: str | None = None, - webhook_secret: str | None = None, - base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = not_given, - max_retries: int = DEFAULT_MAX_RETRIES, - default_headers: Mapping[str, str] | None = None, - default_query: Mapping[str, object] | None = None, - # Configure a custom httpx client. - # We provide a `DefaultAsyncHttpxClient` class that you can pass to retain the default values we use for `limits`, `timeout` & `follow_redirects`. - # See the [httpx documentation](https://www.python-httpx.org/api/#asyncclient) for more details. - http_client: httpx.AsyncClient | None = None, - # Enable or disable schema validation for data returned by the API. - # When enabled an error APIResponseValidationError is raised - # if the API responds with invalid data for the expected schema. - # - # This parameter may be removed or changed in the future. - # If you rely on this feature, please open a GitHub issue - # outlining your use-case to help us decide if it should be - # part of our public interface in the future. - _strict_response_validation: bool = False, - ) -> None: - """Construct a new async AsyncMetronome client instance. - - This automatically infers the following arguments from their corresponding environment variables if they are not provided: - - `bearer_token` from `METRONOME_BEARER_TOKEN` - - `webhook_secret` from `METRONOME_WEBHOOK_SECRET` - """ - if bearer_token is None: - bearer_token = os.environ.get("METRONOME_BEARER_TOKEN") - if bearer_token is None: - raise MetronomeError( - "The bearer_token client option must be set either by passing bearer_token to the client or by setting the METRONOME_BEARER_TOKEN environment variable" - ) - self.bearer_token = bearer_token - - if webhook_secret is None: - webhook_secret = os.environ.get("METRONOME_WEBHOOK_SECRET") - self.webhook_secret = webhook_secret - - if base_url is None: - base_url = os.environ.get("METRONOME_BASE_URL") - if base_url is None: - base_url = f"https://api.metronome.com" - - super().__init__( - version=__version__, - base_url=base_url, - max_retries=max_retries, - timeout=timeout, - http_client=http_client, - custom_headers=default_headers, - custom_query=default_query, - _strict_response_validation=_strict_response_validation, - ) - - @cached_property - def v2(self) -> AsyncV2Resource: - from .resources.v2 import AsyncV2Resource - - return AsyncV2Resource(self) - - @cached_property - def v1(self) -> AsyncV1Resource: - from .resources.v1 import AsyncV1Resource - - return AsyncV1Resource(self) - - @cached_property - def with_raw_response(self) -> AsyncMetronomeWithRawResponse: - return AsyncMetronomeWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncMetronomeWithStreamedResponse: - return AsyncMetronomeWithStreamedResponse(self) - - @property - @override - def qs(self) -> Querystring: - return Querystring(array_format="comma") - - @property - @override - def auth_headers(self) -> dict[str, str]: - bearer_token = self.bearer_token - return {"Authorization": f"Bearer {bearer_token}"} - - @property - @override - def default_headers(self) -> dict[str, str | Omit]: - return { - **super().default_headers, - "X-Stainless-Async": f"async:{get_async_library()}", - **self._custom_headers, - } - - def copy( - self, - *, - bearer_token: str | None = None, - webhook_secret: str | None = None, - base_url: str | httpx.URL | None = None, - timeout: float | Timeout | None | NotGiven = not_given, - http_client: httpx.AsyncClient | None = None, - max_retries: int | NotGiven = not_given, - default_headers: Mapping[str, str] | None = None, - set_default_headers: Mapping[str, str] | None = None, - default_query: Mapping[str, object] | None = None, - set_default_query: Mapping[str, object] | None = None, - _extra_kwargs: Mapping[str, Any] = {}, - ) -> Self: - """ - Create a new client instance re-using the same options given to the current client with optional overriding. - """ - if default_headers is not None and set_default_headers is not None: - raise ValueError("The `default_headers` and `set_default_headers` arguments are mutually exclusive") - - if default_query is not None and set_default_query is not None: - raise ValueError("The `default_query` and `set_default_query` arguments are mutually exclusive") - - headers = self._custom_headers - if default_headers is not None: - headers = {**headers, **default_headers} - elif set_default_headers is not None: - headers = set_default_headers - - params = self._custom_query - if default_query is not None: - params = {**params, **default_query} - elif set_default_query is not None: - params = set_default_query - - http_client = http_client or self._client - return self.__class__( - bearer_token=bearer_token or self.bearer_token, - webhook_secret=webhook_secret or self.webhook_secret, - base_url=base_url or self.base_url, - timeout=self.timeout if isinstance(timeout, NotGiven) else timeout, - http_client=http_client, - max_retries=max_retries if is_given(max_retries) else self.max_retries, - default_headers=headers, - default_query=params, - **_extra_kwargs, - ) - - # Alias for `copy` for nicer inline usage, e.g. - # client.with_options(timeout=10).foo.create(...) - with_options = copy - - @override - def _make_status_error( - self, - err_msg: str, - *, - body: object, - response: httpx.Response, - ) -> APIStatusError: - if response.status_code == 400: - return _exceptions.BadRequestError(err_msg, response=response, body=body) - - if response.status_code == 401: - return _exceptions.AuthenticationError(err_msg, response=response, body=body) - - if response.status_code == 403: - return _exceptions.PermissionDeniedError(err_msg, response=response, body=body) - - if response.status_code == 404: - return _exceptions.NotFoundError(err_msg, response=response, body=body) - - if response.status_code == 409: - return _exceptions.ConflictError(err_msg, response=response, body=body) - - if response.status_code == 422: - return _exceptions.UnprocessableEntityError(err_msg, response=response, body=body) - - if response.status_code == 429: - return _exceptions.RateLimitError(err_msg, response=response, body=body) - - if response.status_code >= 500: - return _exceptions.InternalServerError(err_msg, response=response, body=body) - return APIStatusError(err_msg, response=response, body=body) - - -class MetronomeWithRawResponse: - _client: Metronome - - def __init__(self, client: Metronome) -> None: - self._client = client - - @cached_property - def v2(self) -> v2.V2ResourceWithRawResponse: - from .resources.v2 import V2ResourceWithRawResponse - - return V2ResourceWithRawResponse(self._client.v2) - - @cached_property - def v1(self) -> v1.V1ResourceWithRawResponse: - from .resources.v1 import V1ResourceWithRawResponse - - return V1ResourceWithRawResponse(self._client.v1) - - -class AsyncMetronomeWithRawResponse: - _client: AsyncMetronome - - def __init__(self, client: AsyncMetronome) -> None: - self._client = client - - @cached_property - def v2(self) -> v2.AsyncV2ResourceWithRawResponse: - from .resources.v2 import AsyncV2ResourceWithRawResponse - - return AsyncV2ResourceWithRawResponse(self._client.v2) - - @cached_property - def v1(self) -> v1.AsyncV1ResourceWithRawResponse: - from .resources.v1 import AsyncV1ResourceWithRawResponse - - return AsyncV1ResourceWithRawResponse(self._client.v1) - - -class MetronomeWithStreamedResponse: - _client: Metronome - - def __init__(self, client: Metronome) -> None: - self._client = client - - @cached_property - def v2(self) -> v2.V2ResourceWithStreamingResponse: - from .resources.v2 import V2ResourceWithStreamingResponse - - return V2ResourceWithStreamingResponse(self._client.v2) - - @cached_property - def v1(self) -> v1.V1ResourceWithStreamingResponse: - from .resources.v1 import V1ResourceWithStreamingResponse - - return V1ResourceWithStreamingResponse(self._client.v1) - - -class AsyncMetronomeWithStreamedResponse: - _client: AsyncMetronome - - def __init__(self, client: AsyncMetronome) -> None: - self._client = client - - @cached_property - def v2(self) -> v2.AsyncV2ResourceWithStreamingResponse: - from .resources.v2 import AsyncV2ResourceWithStreamingResponse - - return AsyncV2ResourceWithStreamingResponse(self._client.v2) - - @cached_property - def v1(self) -> v1.AsyncV1ResourceWithStreamingResponse: - from .resources.v1 import AsyncV1ResourceWithStreamingResponse - - return AsyncV1ResourceWithStreamingResponse(self._client.v1) - - -Client = Metronome - -AsyncClient = AsyncMetronome diff --git a/src/metronome/_compat.py b/src/metronome/_compat.py deleted file mode 100644 index 786ff42ad..000000000 --- a/src/metronome/_compat.py +++ /dev/null @@ -1,219 +0,0 @@ -from __future__ import annotations - -from typing import TYPE_CHECKING, Any, Union, Generic, TypeVar, Callable, cast, overload -from datetime import date, datetime -from typing_extensions import Self, Literal - -import pydantic -from pydantic.fields import FieldInfo - -from ._types import IncEx, StrBytesIntFloat - -_T = TypeVar("_T") -_ModelT = TypeVar("_ModelT", bound=pydantic.BaseModel) - -# --------------- Pydantic v2, v3 compatibility --------------- - -# Pyright incorrectly reports some of our functions as overriding a method when they don't -# pyright: reportIncompatibleMethodOverride=false - -PYDANTIC_V1 = pydantic.VERSION.startswith("1.") - -if TYPE_CHECKING: - - def parse_date(value: date | StrBytesIntFloat) -> date: # noqa: ARG001 - ... - - def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: # noqa: ARG001 - ... - - def get_args(t: type[Any]) -> tuple[Any, ...]: # noqa: ARG001 - ... - - def is_union(tp: type[Any] | None) -> bool: # noqa: ARG001 - ... - - def get_origin(t: type[Any]) -> type[Any] | None: # noqa: ARG001 - ... - - def is_literal_type(type_: type[Any]) -> bool: # noqa: ARG001 - ... - - def is_typeddict(type_: type[Any]) -> bool: # noqa: ARG001 - ... - -else: - # v1 re-exports - if PYDANTIC_V1: - from pydantic.typing import ( - get_args as get_args, - is_union as is_union, - get_origin as get_origin, - is_typeddict as is_typeddict, - is_literal_type as is_literal_type, - ) - from pydantic.datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime - else: - from ._utils import ( - get_args as get_args, - is_union as is_union, - get_origin as get_origin, - parse_date as parse_date, - is_typeddict as is_typeddict, - parse_datetime as parse_datetime, - is_literal_type as is_literal_type, - ) - - -# refactored config -if TYPE_CHECKING: - from pydantic import ConfigDict as ConfigDict -else: - if PYDANTIC_V1: - # TODO: provide an error message here? - ConfigDict = None - else: - from pydantic import ConfigDict as ConfigDict - - -# renamed methods / properties -def parse_obj(model: type[_ModelT], value: object) -> _ModelT: - if PYDANTIC_V1: - return cast(_ModelT, model.parse_obj(value)) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] - else: - return model.model_validate(value) - - -def field_is_required(field: FieldInfo) -> bool: - if PYDANTIC_V1: - return field.required # type: ignore - return field.is_required() - - -def field_get_default(field: FieldInfo) -> Any: - value = field.get_default() - if PYDANTIC_V1: - return value - from pydantic_core import PydanticUndefined - - if value == PydanticUndefined: - return None - return value - - -def field_outer_type(field: FieldInfo) -> Any: - if PYDANTIC_V1: - return field.outer_type_ # type: ignore - return field.annotation - - -def get_model_config(model: type[pydantic.BaseModel]) -> Any: - if PYDANTIC_V1: - return model.__config__ # type: ignore - return model.model_config - - -def get_model_fields(model: type[pydantic.BaseModel]) -> dict[str, FieldInfo]: - if PYDANTIC_V1: - return model.__fields__ # type: ignore - return model.model_fields - - -def model_copy(model: _ModelT, *, deep: bool = False) -> _ModelT: - if PYDANTIC_V1: - return model.copy(deep=deep) # type: ignore - return model.model_copy(deep=deep) - - -def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str: - if PYDANTIC_V1: - return model.json(indent=indent) # type: ignore - return model.model_dump_json(indent=indent) - - -def model_dump( - model: pydantic.BaseModel, - *, - exclude: IncEx | None = None, - exclude_unset: bool = False, - exclude_defaults: bool = False, - warnings: bool = True, - mode: Literal["json", "python"] = "python", - by_alias: bool | None = None, -) -> dict[str, Any]: - if (not PYDANTIC_V1) or hasattr(model, "model_dump"): - return model.model_dump( - mode=mode, - exclude=exclude, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - # warnings are not supported in Pydantic v1 - warnings=True if PYDANTIC_V1 else warnings, - by_alias=by_alias, - ) - return cast( - "dict[str, Any]", - model.dict( # pyright: ignore[reportDeprecated, reportUnnecessaryCast] - exclude=exclude, exclude_unset=exclude_unset, exclude_defaults=exclude_defaults, by_alias=bool(by_alias) - ), - ) - - -def model_parse(model: type[_ModelT], data: Any) -> _ModelT: - if PYDANTIC_V1: - return model.parse_obj(data) # pyright: ignore[reportDeprecated] - return model.model_validate(data) - - -# generic models -if TYPE_CHECKING: - - class GenericModel(pydantic.BaseModel): ... - -else: - if PYDANTIC_V1: - import pydantic.generics - - class GenericModel(pydantic.generics.GenericModel, pydantic.BaseModel): ... - else: - # there no longer needs to be a distinction in v2 but - # we still have to create our own subclass to avoid - # inconsistent MRO ordering errors - class GenericModel(pydantic.BaseModel): ... - - -# cached properties -if TYPE_CHECKING: - cached_property = property - - # we define a separate type (copied from typeshed) - # that represents that `cached_property` is `set`able - # at runtime, which differs from `@property`. - # - # this is a separate type as editors likely special case - # `@property` and we don't want to cause issues just to have - # more helpful internal types. - - class typed_cached_property(Generic[_T]): - func: Callable[[Any], _T] - attrname: str | None - - def __init__(self, func: Callable[[Any], _T]) -> None: ... - - @overload - def __get__(self, instance: None, owner: type[Any] | None = None) -> Self: ... - - @overload - def __get__(self, instance: object, owner: type[Any] | None = None) -> _T: ... - - def __get__(self, instance: object, owner: type[Any] | None = None) -> _T | Self: - raise NotImplementedError() - - def __set_name__(self, owner: type[Any], name: str) -> None: ... - - # __set__ is not defined at runtime, but @cached_property is designed to be settable - def __set__(self, instance: object, value: _T) -> None: ... -else: - from functools import cached_property as cached_property - - typed_cached_property = cached_property diff --git a/src/metronome/_constants.py b/src/metronome/_constants.py deleted file mode 100644 index 6ddf2c717..000000000 --- a/src/metronome/_constants.py +++ /dev/null @@ -1,14 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import httpx - -RAW_RESPONSE_HEADER = "X-Stainless-Raw-Response" -OVERRIDE_CAST_TO_HEADER = "____stainless_override_cast_to" - -# default timeout is 1 minute -DEFAULT_TIMEOUT = httpx.Timeout(timeout=60, connect=5.0) -DEFAULT_MAX_RETRIES = 2 -DEFAULT_CONNECTION_LIMITS = httpx.Limits(max_connections=100, max_keepalive_connections=20) - -INITIAL_RETRY_DELAY = 0.5 -MAX_RETRY_DELAY = 8.0 diff --git a/src/metronome/_exceptions.py b/src/metronome/_exceptions.py deleted file mode 100644 index f817b7fb1..000000000 --- a/src/metronome/_exceptions.py +++ /dev/null @@ -1,108 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal - -import httpx - -__all__ = [ - "BadRequestError", - "AuthenticationError", - "PermissionDeniedError", - "NotFoundError", - "ConflictError", - "UnprocessableEntityError", - "RateLimitError", - "InternalServerError", -] - - -class MetronomeError(Exception): - pass - - -class APIError(MetronomeError): - message: str - request: httpx.Request - - body: object | None - """The API response body. - - If the API responded with a valid JSON structure then this property will be the - decoded result. - - If it isn't a valid JSON structure then this will be the raw response. - - If there was no response associated with this error then it will be `None`. - """ - - def __init__(self, message: str, request: httpx.Request, *, body: object | None) -> None: # noqa: ARG002 - super().__init__(message) - self.request = request - self.message = message - self.body = body - - -class APIResponseValidationError(APIError): - response: httpx.Response - status_code: int - - def __init__(self, response: httpx.Response, body: object | None, *, message: str | None = None) -> None: - super().__init__(message or "Data returned by API invalid for expected schema.", response.request, body=body) - self.response = response - self.status_code = response.status_code - - -class APIStatusError(APIError): - """Raised when an API response has a status code of 4xx or 5xx.""" - - response: httpx.Response - status_code: int - - def __init__(self, message: str, *, response: httpx.Response, body: object | None) -> None: - super().__init__(message, response.request, body=body) - self.response = response - self.status_code = response.status_code - - -class APIConnectionError(APIError): - def __init__(self, *, message: str = "Connection error.", request: httpx.Request) -> None: - super().__init__(message, request, body=None) - - -class APITimeoutError(APIConnectionError): - def __init__(self, request: httpx.Request) -> None: - super().__init__(message="Request timed out.", request=request) - - -class BadRequestError(APIStatusError): - status_code: Literal[400] = 400 # pyright: ignore[reportIncompatibleVariableOverride] - - -class AuthenticationError(APIStatusError): - status_code: Literal[401] = 401 # pyright: ignore[reportIncompatibleVariableOverride] - - -class PermissionDeniedError(APIStatusError): - status_code: Literal[403] = 403 # pyright: ignore[reportIncompatibleVariableOverride] - - -class NotFoundError(APIStatusError): - status_code: Literal[404] = 404 # pyright: ignore[reportIncompatibleVariableOverride] - - -class ConflictError(APIStatusError): - status_code: Literal[409] = 409 # pyright: ignore[reportIncompatibleVariableOverride] - - -class UnprocessableEntityError(APIStatusError): - status_code: Literal[422] = 422 # pyright: ignore[reportIncompatibleVariableOverride] - - -class RateLimitError(APIStatusError): - status_code: Literal[429] = 429 # pyright: ignore[reportIncompatibleVariableOverride] - - -class InternalServerError(APIStatusError): - pass diff --git a/src/metronome/_files.py b/src/metronome/_files.py deleted file mode 100644 index cc14c14f6..000000000 --- a/src/metronome/_files.py +++ /dev/null @@ -1,123 +0,0 @@ -from __future__ import annotations - -import io -import os -import pathlib -from typing import overload -from typing_extensions import TypeGuard - -import anyio - -from ._types import ( - FileTypes, - FileContent, - RequestFiles, - HttpxFileTypes, - Base64FileInput, - HttpxFileContent, - HttpxRequestFiles, -) -from ._utils import is_tuple_t, is_mapping_t, is_sequence_t - - -def is_base64_file_input(obj: object) -> TypeGuard[Base64FileInput]: - return isinstance(obj, io.IOBase) or isinstance(obj, os.PathLike) - - -def is_file_content(obj: object) -> TypeGuard[FileContent]: - return ( - isinstance(obj, bytes) or isinstance(obj, tuple) or isinstance(obj, io.IOBase) or isinstance(obj, os.PathLike) - ) - - -def assert_is_file_content(obj: object, *, key: str | None = None) -> None: - if not is_file_content(obj): - prefix = f"Expected entry at `{key}`" if key is not None else f"Expected file input `{obj!r}`" - raise RuntimeError( - f"{prefix} to be bytes, an io.IOBase instance, PathLike or a tuple but received {type(obj)} instead." - ) from None - - -@overload -def to_httpx_files(files: None) -> None: ... - - -@overload -def to_httpx_files(files: RequestFiles) -> HttpxRequestFiles: ... - - -def to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles | None: - if files is None: - return None - - if is_mapping_t(files): - files = {key: _transform_file(file) for key, file in files.items()} - elif is_sequence_t(files): - files = [(key, _transform_file(file)) for key, file in files] - else: - raise TypeError(f"Unexpected file type input {type(files)}, expected mapping or sequence") - - return files - - -def _transform_file(file: FileTypes) -> HttpxFileTypes: - if is_file_content(file): - if isinstance(file, os.PathLike): - path = pathlib.Path(file) - return (path.name, path.read_bytes()) - - return file - - if is_tuple_t(file): - return (file[0], read_file_content(file[1]), *file[2:]) - - raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple") - - -def read_file_content(file: FileContent) -> HttpxFileContent: - if isinstance(file, os.PathLike): - return pathlib.Path(file).read_bytes() - return file - - -@overload -async def async_to_httpx_files(files: None) -> None: ... - - -@overload -async def async_to_httpx_files(files: RequestFiles) -> HttpxRequestFiles: ... - - -async def async_to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles | None: - if files is None: - return None - - if is_mapping_t(files): - files = {key: await _async_transform_file(file) for key, file in files.items()} - elif is_sequence_t(files): - files = [(key, await _async_transform_file(file)) for key, file in files] - else: - raise TypeError("Unexpected file type input {type(files)}, expected mapping or sequence") - - return files - - -async def _async_transform_file(file: FileTypes) -> HttpxFileTypes: - if is_file_content(file): - if isinstance(file, os.PathLike): - path = anyio.Path(file) - return (path.name, await path.read_bytes()) - - return file - - if is_tuple_t(file): - return (file[0], await async_read_file_content(file[1]), *file[2:]) - - raise TypeError(f"Expected file types input to be a FileContent type or to be a tuple") - - -async def async_read_file_content(file: FileContent) -> HttpxFileContent: - if isinstance(file, os.PathLike): - return await anyio.Path(file).read_bytes() - - return file diff --git a/src/metronome/_models.py b/src/metronome/_models.py deleted file mode 100644 index 29070e055..000000000 --- a/src/metronome/_models.py +++ /dev/null @@ -1,872 +0,0 @@ -from __future__ import annotations - -import os -import inspect -import weakref -from typing import ( - IO, - TYPE_CHECKING, - Any, - Type, - Union, - Generic, - TypeVar, - Callable, - Iterable, - Optional, - AsyncIterable, - cast, -) -from datetime import date, datetime -from typing_extensions import ( - List, - Unpack, - Literal, - ClassVar, - Protocol, - Required, - ParamSpec, - TypedDict, - TypeGuard, - final, - override, - runtime_checkable, -) - -import pydantic -from pydantic.fields import FieldInfo - -from ._types import ( - Body, - IncEx, - Query, - ModelT, - Headers, - Timeout, - NotGiven, - AnyMapping, - HttpxRequestFiles, -) -from ._utils import ( - PropertyInfo, - is_list, - is_given, - json_safe, - lru_cache, - is_mapping, - parse_date, - coerce_boolean, - parse_datetime, - strip_not_given, - extract_type_arg, - is_annotated_type, - is_type_alias_type, - strip_annotated_type, -) -from ._compat import ( - PYDANTIC_V1, - ConfigDict, - GenericModel as BaseGenericModel, - get_args, - is_union, - parse_obj, - get_origin, - is_literal_type, - get_model_config, - get_model_fields, - field_get_default, -) -from ._constants import RAW_RESPONSE_HEADER - -if TYPE_CHECKING: - from pydantic_core.core_schema import ModelField, ModelSchema, LiteralSchema, ModelFieldsSchema - -__all__ = ["BaseModel", "GenericModel"] - -_T = TypeVar("_T") -_BaseModelT = TypeVar("_BaseModelT", bound="BaseModel") - -P = ParamSpec("P") - - -@runtime_checkable -class _ConfigProtocol(Protocol): - allow_population_by_field_name: bool - - -class BaseModel(pydantic.BaseModel): - if PYDANTIC_V1: - - @property - @override - def model_fields_set(self) -> set[str]: - # a forwards-compat shim for pydantic v2 - return self.__fields_set__ # type: ignore - - class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] - extra: Any = pydantic.Extra.allow # type: ignore - else: - model_config: ClassVar[ConfigDict] = ConfigDict( - extra="allow", defer_build=coerce_boolean(os.environ.get("DEFER_PYDANTIC_BUILD", "true")) - ) - - def to_dict( - self, - *, - mode: Literal["json", "python"] = "python", - use_api_names: bool = True, - exclude_unset: bool = True, - exclude_defaults: bool = False, - exclude_none: bool = False, - warnings: bool = True, - ) -> dict[str, object]: - """Recursively generate a dictionary representation of the model, optionally specifying which fields to include or exclude. - - By default, fields that were not set by the API will not be included, - and keys will match the API response, *not* the property names from the model. - - For example, if the API responds with `"fooBar": true` but we've defined a `foo_bar: bool` property, - the output will use the `"fooBar"` key (unless `use_api_names=False` is passed). - - Args: - mode: - If mode is 'json', the dictionary will only contain JSON serializable types. e.g. `datetime` will be turned into a string, `"2024-3-22T18:11:19.117000Z"`. - If mode is 'python', the dictionary may contain any Python objects. e.g. `datetime(2024, 3, 22)` - - use_api_names: Whether to use the key that the API responded with or the property name. Defaults to `True`. - exclude_unset: Whether to exclude fields that have not been explicitly set. - exclude_defaults: Whether to exclude fields that are set to their default value from the output. - exclude_none: Whether to exclude fields that have a value of `None` from the output. - warnings: Whether to log warnings when invalid fields are encountered. This is only supported in Pydantic v2. - """ - return self.model_dump( - mode=mode, - by_alias=use_api_names, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - exclude_none=exclude_none, - warnings=warnings, - ) - - def to_json( - self, - *, - indent: int | None = 2, - use_api_names: bool = True, - exclude_unset: bool = True, - exclude_defaults: bool = False, - exclude_none: bool = False, - warnings: bool = True, - ) -> str: - """Generates a JSON string representing this model as it would be received from or sent to the API (but with indentation). - - By default, fields that were not set by the API will not be included, - and keys will match the API response, *not* the property names from the model. - - For example, if the API responds with `"fooBar": true` but we've defined a `foo_bar: bool` property, - the output will use the `"fooBar"` key (unless `use_api_names=False` is passed). - - Args: - indent: Indentation to use in the JSON output. If `None` is passed, the output will be compact. Defaults to `2` - use_api_names: Whether to use the key that the API responded with or the property name. Defaults to `True`. - exclude_unset: Whether to exclude fields that have not been explicitly set. - exclude_defaults: Whether to exclude fields that have the default value. - exclude_none: Whether to exclude fields that have a value of `None`. - warnings: Whether to show any warnings that occurred during serialization. This is only supported in Pydantic v2. - """ - return self.model_dump_json( - indent=indent, - by_alias=use_api_names, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - exclude_none=exclude_none, - warnings=warnings, - ) - - @override - def __str__(self) -> str: - # mypy complains about an invalid self arg - return f"{self.__repr_name__()}({self.__repr_str__(', ')})" # type: ignore[misc] - - # Override the 'construct' method in a way that supports recursive parsing without validation. - # Based on https://github.com/samuelcolvin/pydantic/issues/1168#issuecomment-817742836. - @classmethod - @override - def construct( # pyright: ignore[reportIncompatibleMethodOverride] - __cls: Type[ModelT], - _fields_set: set[str] | None = None, - **values: object, - ) -> ModelT: - m = __cls.__new__(__cls) - fields_values: dict[str, object] = {} - - config = get_model_config(__cls) - populate_by_name = ( - config.allow_population_by_field_name - if isinstance(config, _ConfigProtocol) - else config.get("populate_by_name") - ) - - if _fields_set is None: - _fields_set = set() - - model_fields = get_model_fields(__cls) - for name, field in model_fields.items(): - key = field.alias - if key is None or (key not in values and populate_by_name): - key = name - - if key in values: - fields_values[name] = _construct_field(value=values[key], field=field, key=key) - _fields_set.add(name) - else: - fields_values[name] = field_get_default(field) - - extra_field_type = _get_extra_fields_type(__cls) - - _extra = {} - for key, value in values.items(): - if key not in model_fields: - parsed = construct_type(value=value, type_=extra_field_type) if extra_field_type is not None else value - - if PYDANTIC_V1: - _fields_set.add(key) - fields_values[key] = parsed - else: - _extra[key] = parsed - - object.__setattr__(m, "__dict__", fields_values) - - if PYDANTIC_V1: - # init_private_attributes() does not exist in v2 - m._init_private_attributes() # type: ignore - - # copied from Pydantic v1's `construct()` method - object.__setattr__(m, "__fields_set__", _fields_set) - else: - # these properties are copied from Pydantic's `model_construct()` method - object.__setattr__(m, "__pydantic_private__", None) - object.__setattr__(m, "__pydantic_extra__", _extra) - object.__setattr__(m, "__pydantic_fields_set__", _fields_set) - - return m - - if not TYPE_CHECKING: - # type checkers incorrectly complain about this assignment - # because the type signatures are technically different - # although not in practice - model_construct = construct - - if PYDANTIC_V1: - # we define aliases for some of the new pydantic v2 methods so - # that we can just document these methods without having to specify - # a specific pydantic version as some users may not know which - # pydantic version they are currently using - - @override - def model_dump( - self, - *, - mode: Literal["json", "python"] | str = "python", - include: IncEx | None = None, - exclude: IncEx | None = None, - context: Any | None = None, - by_alias: bool | None = None, - exclude_unset: bool = False, - exclude_defaults: bool = False, - exclude_none: bool = False, - exclude_computed_fields: bool = False, - round_trip: bool = False, - warnings: bool | Literal["none", "warn", "error"] = True, - fallback: Callable[[Any], Any] | None = None, - serialize_as_any: bool = False, - ) -> dict[str, Any]: - """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump - - Generate a dictionary representation of the model, optionally specifying which fields to include or exclude. - - Args: - mode: The mode in which `to_python` should run. - If mode is 'json', the output will only contain JSON serializable types. - If mode is 'python', the output may contain non-JSON-serializable Python objects. - include: A set of fields to include in the output. - exclude: A set of fields to exclude from the output. - context: Additional context to pass to the serializer. - by_alias: Whether to use the field's alias in the dictionary key if defined. - exclude_unset: Whether to exclude fields that have not been explicitly set. - exclude_defaults: Whether to exclude fields that are set to their default value. - exclude_none: Whether to exclude fields that have a value of `None`. - exclude_computed_fields: Whether to exclude computed fields. - While this can be useful for round-tripping, it is usually recommended to use the dedicated - `round_trip` parameter instead. - round_trip: If True, dumped values should be valid as input for non-idempotent types such as Json[T]. - warnings: How to handle serialization errors. False/"none" ignores them, True/"warn" logs errors, - "error" raises a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError]. - fallback: A function to call when an unknown value is encountered. If not provided, - a [`PydanticSerializationError`][pydantic_core.PydanticSerializationError] error is raised. - serialize_as_any: Whether to serialize fields with duck-typing serialization behavior. - - Returns: - A dictionary representation of the model. - """ - if mode not in {"json", "python"}: - raise ValueError("mode must be either 'json' or 'python'") - if round_trip != False: - raise ValueError("round_trip is only supported in Pydantic v2") - if warnings != True: - raise ValueError("warnings is only supported in Pydantic v2") - if context is not None: - raise ValueError("context is only supported in Pydantic v2") - if serialize_as_any != False: - raise ValueError("serialize_as_any is only supported in Pydantic v2") - if fallback is not None: - raise ValueError("fallback is only supported in Pydantic v2") - if exclude_computed_fields != False: - raise ValueError("exclude_computed_fields is only supported in Pydantic v2") - dumped = super().dict( # pyright: ignore[reportDeprecated] - include=include, - exclude=exclude, - by_alias=by_alias if by_alias is not None else False, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - exclude_none=exclude_none, - ) - - return cast("dict[str, Any]", json_safe(dumped)) if mode == "json" else dumped - - @override - def model_dump_json( - self, - *, - indent: int | None = None, - ensure_ascii: bool = False, - include: IncEx | None = None, - exclude: IncEx | None = None, - context: Any | None = None, - by_alias: bool | None = None, - exclude_unset: bool = False, - exclude_defaults: bool = False, - exclude_none: bool = False, - exclude_computed_fields: bool = False, - round_trip: bool = False, - warnings: bool | Literal["none", "warn", "error"] = True, - fallback: Callable[[Any], Any] | None = None, - serialize_as_any: bool = False, - ) -> str: - """Usage docs: https://docs.pydantic.dev/2.4/concepts/serialization/#modelmodel_dump_json - - Generates a JSON representation of the model using Pydantic's `to_json` method. - - Args: - indent: Indentation to use in the JSON output. If None is passed, the output will be compact. - include: Field(s) to include in the JSON output. Can take either a string or set of strings. - exclude: Field(s) to exclude from the JSON output. Can take either a string or set of strings. - by_alias: Whether to serialize using field aliases. - exclude_unset: Whether to exclude fields that have not been explicitly set. - exclude_defaults: Whether to exclude fields that have the default value. - exclude_none: Whether to exclude fields that have a value of `None`. - round_trip: Whether to use serialization/deserialization between JSON and class instance. - warnings: Whether to show any warnings that occurred during serialization. - - Returns: - A JSON string representation of the model. - """ - if round_trip != False: - raise ValueError("round_trip is only supported in Pydantic v2") - if warnings != True: - raise ValueError("warnings is only supported in Pydantic v2") - if context is not None: - raise ValueError("context is only supported in Pydantic v2") - if serialize_as_any != False: - raise ValueError("serialize_as_any is only supported in Pydantic v2") - if fallback is not None: - raise ValueError("fallback is only supported in Pydantic v2") - if ensure_ascii != False: - raise ValueError("ensure_ascii is only supported in Pydantic v2") - if exclude_computed_fields != False: - raise ValueError("exclude_computed_fields is only supported in Pydantic v2") - return super().json( # type: ignore[reportDeprecated] - indent=indent, - include=include, - exclude=exclude, - by_alias=by_alias if by_alias is not None else False, - exclude_unset=exclude_unset, - exclude_defaults=exclude_defaults, - exclude_none=exclude_none, - ) - - -def _construct_field(value: object, field: FieldInfo, key: str) -> object: - if value is None: - return field_get_default(field) - - if PYDANTIC_V1: - type_ = cast(type, field.outer_type_) # type: ignore - else: - type_ = field.annotation # type: ignore - - if type_ is None: - raise RuntimeError(f"Unexpected field type is None for {key}") - - return construct_type(value=value, type_=type_, metadata=getattr(field, "metadata", None)) - - -def _get_extra_fields_type(cls: type[pydantic.BaseModel]) -> type | None: - if PYDANTIC_V1: - # TODO - return None - - schema = cls.__pydantic_core_schema__ - if schema["type"] == "model": - fields = schema["schema"] - if fields["type"] == "model-fields": - extras = fields.get("extras_schema") - if extras and "cls" in extras: - # mypy can't narrow the type - return extras["cls"] # type: ignore[no-any-return] - - return None - - -def is_basemodel(type_: type) -> bool: - """Returns whether or not the given type is either a `BaseModel` or a union of `BaseModel`""" - if is_union(type_): - for variant in get_args(type_): - if is_basemodel(variant): - return True - - return False - - return is_basemodel_type(type_) - - -def is_basemodel_type(type_: type) -> TypeGuard[type[BaseModel] | type[GenericModel]]: - origin = get_origin(type_) or type_ - if not inspect.isclass(origin): - return False - return issubclass(origin, BaseModel) or issubclass(origin, GenericModel) - - -def build( - base_model_cls: Callable[P, _BaseModelT], - *args: P.args, - **kwargs: P.kwargs, -) -> _BaseModelT: - """Construct a BaseModel class without validation. - - This is useful for cases where you need to instantiate a `BaseModel` - from an API response as this provides type-safe params which isn't supported - by helpers like `construct_type()`. - - ```py - build(MyModel, my_field_a="foo", my_field_b=123) - ``` - """ - if args: - raise TypeError( - "Received positional arguments which are not supported; Keyword arguments must be used instead", - ) - - return cast(_BaseModelT, construct_type(type_=base_model_cls, value=kwargs)) - - -def construct_type_unchecked(*, value: object, type_: type[_T]) -> _T: - """Loose coercion to the expected type with construction of nested values. - - Note: the returned value from this function is not guaranteed to match the - given type. - """ - return cast(_T, construct_type(value=value, type_=type_)) - - -def construct_type(*, value: object, type_: object, metadata: Optional[List[Any]] = None) -> object: - """Loose coercion to the expected type with construction of nested values. - - If the given value does not match the expected type then it is returned as-is. - """ - - # store a reference to the original type we were given before we extract any inner - # types so that we can properly resolve forward references in `TypeAliasType` annotations - original_type = None - - # we allow `object` as the input type because otherwise, passing things like - # `Literal['value']` will be reported as a type error by type checkers - type_ = cast("type[object]", type_) - if is_type_alias_type(type_): - original_type = type_ # type: ignore[unreachable] - type_ = type_.__value__ # type: ignore[unreachable] - - # unwrap `Annotated[T, ...]` -> `T` - if metadata is not None and len(metadata) > 0: - meta: tuple[Any, ...] = tuple(metadata) - elif is_annotated_type(type_): - meta = get_args(type_)[1:] - type_ = extract_type_arg(type_, 0) - else: - meta = tuple() - - # we need to use the origin class for any types that are subscripted generics - # e.g. Dict[str, object] - origin = get_origin(type_) or type_ - args = get_args(type_) - - if is_union(origin): - try: - return validate_type(type_=cast("type[object]", original_type or type_), value=value) - except Exception: - pass - - # if the type is a discriminated union then we want to construct the right variant - # in the union, even if the data doesn't match exactly, otherwise we'd break code - # that relies on the constructed class types, e.g. - # - # class FooType: - # kind: Literal['foo'] - # value: str - # - # class BarType: - # kind: Literal['bar'] - # value: int - # - # without this block, if the data we get is something like `{'kind': 'bar', 'value': 'foo'}` then - # we'd end up constructing `FooType` when it should be `BarType`. - discriminator = _build_discriminated_union_meta(union=type_, meta_annotations=meta) - if discriminator and is_mapping(value): - variant_value = value.get(discriminator.field_alias_from or discriminator.field_name) - if variant_value and isinstance(variant_value, str): - variant_type = discriminator.mapping.get(variant_value) - if variant_type: - return construct_type(type_=variant_type, value=value) - - # if the data is not valid, use the first variant that doesn't fail while deserializing - for variant in args: - try: - return construct_type(value=value, type_=variant) - except Exception: - continue - - raise RuntimeError(f"Could not convert data into a valid instance of {type_}") - - if origin == dict: - if not is_mapping(value): - return value - - _, items_type = get_args(type_) # Dict[_, items_type] - return {key: construct_type(value=item, type_=items_type) for key, item in value.items()} - - if ( - not is_literal_type(type_) - and inspect.isclass(origin) - and (issubclass(origin, BaseModel) or issubclass(origin, GenericModel)) - ): - if is_list(value): - return [cast(Any, type_).construct(**entry) if is_mapping(entry) else entry for entry in value] - - if is_mapping(value): - if issubclass(type_, BaseModel): - return type_.construct(**value) # type: ignore[arg-type] - - return cast(Any, type_).construct(**value) - - if origin == list: - if not is_list(value): - return value - - inner_type = args[0] # List[inner_type] - return [construct_type(value=entry, type_=inner_type) for entry in value] - - if origin == float: - if isinstance(value, int): - coerced = float(value) - if coerced != value: - return value - return coerced - - return value - - if type_ == datetime: - try: - return parse_datetime(value) # type: ignore - except Exception: - return value - - if type_ == date: - try: - return parse_date(value) # type: ignore - except Exception: - return value - - return value - - -@runtime_checkable -class CachedDiscriminatorType(Protocol): - __discriminator__: DiscriminatorDetails - - -DISCRIMINATOR_CACHE: weakref.WeakKeyDictionary[type, DiscriminatorDetails] = weakref.WeakKeyDictionary() - - -class DiscriminatorDetails: - field_name: str - """The name of the discriminator field in the variant class, e.g. - - ```py - class Foo(BaseModel): - type: Literal['foo'] - ``` - - Will result in field_name='type' - """ - - field_alias_from: str | None - """The name of the discriminator field in the API response, e.g. - - ```py - class Foo(BaseModel): - type: Literal['foo'] = Field(alias='type_from_api') - ``` - - Will result in field_alias_from='type_from_api' - """ - - mapping: dict[str, type] - """Mapping of discriminator value to variant type, e.g. - - {'foo': FooVariant, 'bar': BarVariant} - """ - - def __init__( - self, - *, - mapping: dict[str, type], - discriminator_field: str, - discriminator_alias: str | None, - ) -> None: - self.mapping = mapping - self.field_name = discriminator_field - self.field_alias_from = discriminator_alias - - -def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, ...]) -> DiscriminatorDetails | None: - cached = DISCRIMINATOR_CACHE.get(union) - if cached is not None: - return cached - - discriminator_field_name: str | None = None - - for annotation in meta_annotations: - if isinstance(annotation, PropertyInfo) and annotation.discriminator is not None: - discriminator_field_name = annotation.discriminator - break - - if not discriminator_field_name: - return None - - mapping: dict[str, type] = {} - discriminator_alias: str | None = None - - for variant in get_args(union): - variant = strip_annotated_type(variant) - if is_basemodel_type(variant): - if PYDANTIC_V1: - field_info = cast("dict[str, FieldInfo]", variant.__fields__).get(discriminator_field_name) # pyright: ignore[reportDeprecated, reportUnnecessaryCast] - if not field_info: - continue - - # Note: if one variant defines an alias then they all should - discriminator_alias = field_info.alias - - if (annotation := getattr(field_info, "annotation", None)) and is_literal_type(annotation): - for entry in get_args(annotation): - if isinstance(entry, str): - mapping[entry] = variant - else: - field = _extract_field_schema_pv2(variant, discriminator_field_name) - if not field: - continue - - # Note: if one variant defines an alias then they all should - discriminator_alias = field.get("serialization_alias") - - field_schema = field["schema"] - - if field_schema["type"] == "literal": - for entry in cast("LiteralSchema", field_schema)["expected"]: - if isinstance(entry, str): - mapping[entry] = variant - - if not mapping: - return None - - details = DiscriminatorDetails( - mapping=mapping, - discriminator_field=discriminator_field_name, - discriminator_alias=discriminator_alias, - ) - DISCRIMINATOR_CACHE.setdefault(union, details) - return details - - -def _extract_field_schema_pv2(model: type[BaseModel], field_name: str) -> ModelField | None: - schema = model.__pydantic_core_schema__ - if schema["type"] == "definitions": - schema = schema["schema"] - - if schema["type"] != "model": - return None - - schema = cast("ModelSchema", schema) - fields_schema = schema["schema"] - if fields_schema["type"] != "model-fields": - return None - - fields_schema = cast("ModelFieldsSchema", fields_schema) - field = fields_schema["fields"].get(field_name) - if not field: - return None - - return cast("ModelField", field) # pyright: ignore[reportUnnecessaryCast] - - -def validate_type(*, type_: type[_T], value: object) -> _T: - """Strict validation that the given value matches the expected type""" - if inspect.isclass(type_) and issubclass(type_, pydantic.BaseModel): - return cast(_T, parse_obj(type_, value)) - - return cast(_T, _validate_non_model_type(type_=type_, value=value)) - - -def set_pydantic_config(typ: Any, config: pydantic.ConfigDict) -> None: - """Add a pydantic config for the given type. - - Note: this is a no-op on Pydantic v1. - """ - setattr(typ, "__pydantic_config__", config) # noqa: B010 - - -# our use of subclassing here causes weirdness for type checkers, -# so we just pretend that we don't subclass -if TYPE_CHECKING: - GenericModel = BaseModel -else: - - class GenericModel(BaseGenericModel, BaseModel): - pass - - -if not PYDANTIC_V1: - from pydantic import TypeAdapter as _TypeAdapter - - _CachedTypeAdapter = cast("TypeAdapter[object]", lru_cache(maxsize=None)(_TypeAdapter)) - - if TYPE_CHECKING: - from pydantic import TypeAdapter - else: - TypeAdapter = _CachedTypeAdapter - - def _validate_non_model_type(*, type_: type[_T], value: object) -> _T: - return TypeAdapter(type_).validate_python(value) - -elif not TYPE_CHECKING: # TODO: condition is weird - - class RootModel(GenericModel, Generic[_T]): - """Used as a placeholder to easily convert runtime types to a Pydantic format - to provide validation. - - For example: - ```py - validated = RootModel[int](__root__="5").__root__ - # validated: 5 - ``` - """ - - __root__: _T - - def _validate_non_model_type(*, type_: type[_T], value: object) -> _T: - model = _create_pydantic_model(type_).validate(value) - return cast(_T, model.__root__) - - def _create_pydantic_model(type_: _T) -> Type[RootModel[_T]]: - return RootModel[type_] # type: ignore - - -class FinalRequestOptionsInput(TypedDict, total=False): - method: Required[str] - url: Required[str] - params: Query - headers: Headers - max_retries: int - timeout: float | Timeout | None - files: HttpxRequestFiles | None - idempotency_key: str - content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None] - json_data: Body - extra_json: AnyMapping - follow_redirects: bool - - -@final -class FinalRequestOptions(pydantic.BaseModel): - method: str - url: str - params: Query = {} - headers: Union[Headers, NotGiven] = NotGiven() - max_retries: Union[int, NotGiven] = NotGiven() - timeout: Union[float, Timeout, None, NotGiven] = NotGiven() - files: Union[HttpxRequestFiles, None] = None - idempotency_key: Union[str, None] = None - post_parser: Union[Callable[[Any], Any], NotGiven] = NotGiven() - follow_redirects: Union[bool, None] = None - - content: Union[bytes, bytearray, IO[bytes], Iterable[bytes], AsyncIterable[bytes], None] = None - # It should be noted that we cannot use `json` here as that would override - # a BaseModel method in an incompatible fashion. - json_data: Union[Body, None] = None - extra_json: Union[AnyMapping, None] = None - - if PYDANTIC_V1: - - class Config(pydantic.BaseConfig): # pyright: ignore[reportDeprecated] - arbitrary_types_allowed: bool = True - else: - model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True) - - def get_max_retries(self, max_retries: int) -> int: - if isinstance(self.max_retries, NotGiven): - return max_retries - return self.max_retries - - def _strip_raw_response_header(self) -> None: - if not is_given(self.headers): - return - - if self.headers.get(RAW_RESPONSE_HEADER): - self.headers = {**self.headers} - self.headers.pop(RAW_RESPONSE_HEADER) - - # override the `construct` method so that we can run custom transformations. - # this is necessary as we don't want to do any actual runtime type checking - # (which means we can't use validators) but we do want to ensure that `NotGiven` - # values are not present - # - # type ignore required because we're adding explicit types to `**values` - @classmethod - def construct( # type: ignore - cls, - _fields_set: set[str] | None = None, - **values: Unpack[FinalRequestOptionsInput], - ) -> FinalRequestOptions: - kwargs: dict[str, Any] = { - # we unconditionally call `strip_not_given` on any value - # as it will just ignore any non-mapping types - key: strip_not_given(value) - for key, value in values.items() - } - if PYDANTIC_V1: - return cast(FinalRequestOptions, super().construct(_fields_set, **kwargs)) # pyright: ignore[reportDeprecated] - return super().model_construct(_fields_set, **kwargs) - - if not TYPE_CHECKING: - # type checkers incorrectly complain about this assignment - model_construct = construct diff --git a/src/metronome/_qs.py b/src/metronome/_qs.py deleted file mode 100644 index ada6fd3f7..000000000 --- a/src/metronome/_qs.py +++ /dev/null @@ -1,150 +0,0 @@ -from __future__ import annotations - -from typing import Any, List, Tuple, Union, Mapping, TypeVar -from urllib.parse import parse_qs, urlencode -from typing_extensions import Literal, get_args - -from ._types import NotGiven, not_given -from ._utils import flatten - -_T = TypeVar("_T") - - -ArrayFormat = Literal["comma", "repeat", "indices", "brackets"] -NestedFormat = Literal["dots", "brackets"] - -PrimitiveData = Union[str, int, float, bool, None] -# this should be Data = Union[PrimitiveData, "List[Data]", "Tuple[Data]", "Mapping[str, Data]"] -# https://github.com/microsoft/pyright/issues/3555 -Data = Union[PrimitiveData, List[Any], Tuple[Any], "Mapping[str, Any]"] -Params = Mapping[str, Data] - - -class Querystring: - array_format: ArrayFormat - nested_format: NestedFormat - - def __init__( - self, - *, - array_format: ArrayFormat = "repeat", - nested_format: NestedFormat = "brackets", - ) -> None: - self.array_format = array_format - self.nested_format = nested_format - - def parse(self, query: str) -> Mapping[str, object]: - # Note: custom format syntax is not supported yet - return parse_qs(query) - - def stringify( - self, - params: Params, - *, - array_format: ArrayFormat | NotGiven = not_given, - nested_format: NestedFormat | NotGiven = not_given, - ) -> str: - return urlencode( - self.stringify_items( - params, - array_format=array_format, - nested_format=nested_format, - ) - ) - - def stringify_items( - self, - params: Params, - *, - array_format: ArrayFormat | NotGiven = not_given, - nested_format: NestedFormat | NotGiven = not_given, - ) -> list[tuple[str, str]]: - opts = Options( - qs=self, - array_format=array_format, - nested_format=nested_format, - ) - return flatten([self._stringify_item(key, value, opts) for key, value in params.items()]) - - def _stringify_item( - self, - key: str, - value: Data, - opts: Options, - ) -> list[tuple[str, str]]: - if isinstance(value, Mapping): - items: list[tuple[str, str]] = [] - nested_format = opts.nested_format - for subkey, subvalue in value.items(): - items.extend( - self._stringify_item( - # TODO: error if unknown format - f"{key}.{subkey}" if nested_format == "dots" else f"{key}[{subkey}]", - subvalue, - opts, - ) - ) - return items - - if isinstance(value, (list, tuple)): - array_format = opts.array_format - if array_format == "comma": - return [ - ( - key, - ",".join(self._primitive_value_to_str(item) for item in value if item is not None), - ), - ] - elif array_format == "repeat": - items = [] - for item in value: - items.extend(self._stringify_item(key, item, opts)) - return items - elif array_format == "indices": - raise NotImplementedError("The array indices format is not supported yet") - elif array_format == "brackets": - items = [] - key = key + "[]" - for item in value: - items.extend(self._stringify_item(key, item, opts)) - return items - else: - raise NotImplementedError( - f"Unknown array_format value: {array_format}, choose from {', '.join(get_args(ArrayFormat))}" - ) - - serialised = self._primitive_value_to_str(value) - if not serialised: - return [] - return [(key, serialised)] - - def _primitive_value_to_str(self, value: PrimitiveData) -> str: - # copied from httpx - if value is True: - return "true" - elif value is False: - return "false" - elif value is None: - return "" - return str(value) - - -_qs = Querystring() -parse = _qs.parse -stringify = _qs.stringify -stringify_items = _qs.stringify_items - - -class Options: - array_format: ArrayFormat - nested_format: NestedFormat - - def __init__( - self, - qs: Querystring = _qs, - *, - array_format: ArrayFormat | NotGiven = not_given, - nested_format: NestedFormat | NotGiven = not_given, - ) -> None: - self.array_format = qs.array_format if isinstance(array_format, NotGiven) else array_format - self.nested_format = qs.nested_format if isinstance(nested_format, NotGiven) else nested_format diff --git a/src/metronome/_resource.py b/src/metronome/_resource.py deleted file mode 100644 index 5c02333b7..000000000 --- a/src/metronome/_resource.py +++ /dev/null @@ -1,43 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import time -from typing import TYPE_CHECKING - -import anyio - -if TYPE_CHECKING: - from ._client import Metronome, AsyncMetronome - - -class SyncAPIResource: - _client: Metronome - - def __init__(self, client: Metronome) -> None: - self._client = client - self._get = client.get - self._post = client.post - self._patch = client.patch - self._put = client.put - self._delete = client.delete - self._get_api_list = client.get_api_list - - def _sleep(self, seconds: float) -> None: - time.sleep(seconds) - - -class AsyncAPIResource: - _client: AsyncMetronome - - def __init__(self, client: AsyncMetronome) -> None: - self._client = client - self._get = client.get - self._post = client.post - self._patch = client.patch - self._put = client.put - self._delete = client.delete - self._get_api_list = client.get_api_list - - async def _sleep(self, seconds: float) -> None: - await anyio.sleep(seconds) diff --git a/src/metronome/_response.py b/src/metronome/_response.py deleted file mode 100644 index 9d7a1140d..000000000 --- a/src/metronome/_response.py +++ /dev/null @@ -1,833 +0,0 @@ -from __future__ import annotations - -import os -import inspect -import logging -import datetime -import functools -from types import TracebackType -from typing import ( - TYPE_CHECKING, - Any, - Union, - Generic, - TypeVar, - Callable, - Iterator, - AsyncIterator, - cast, - overload, -) -from typing_extensions import Awaitable, ParamSpec, override, get_origin - -import anyio -import httpx -import pydantic - -from ._types import NoneType -from ._utils import is_given, extract_type_arg, is_annotated_type, is_type_alias_type, extract_type_var_from_base -from ._models import BaseModel, is_basemodel -from ._constants import RAW_RESPONSE_HEADER, OVERRIDE_CAST_TO_HEADER -from ._streaming import Stream, AsyncStream, is_stream_class_type, extract_stream_chunk_type -from ._exceptions import MetronomeError, APIResponseValidationError - -if TYPE_CHECKING: - from ._models import FinalRequestOptions - from ._base_client import BaseClient - - -P = ParamSpec("P") -R = TypeVar("R") -_T = TypeVar("_T") -_APIResponseT = TypeVar("_APIResponseT", bound="APIResponse[Any]") -_AsyncAPIResponseT = TypeVar("_AsyncAPIResponseT", bound="AsyncAPIResponse[Any]") - -log: logging.Logger = logging.getLogger(__name__) - - -class BaseAPIResponse(Generic[R]): - _cast_to: type[R] - _client: BaseClient[Any, Any] - _parsed_by_type: dict[type[Any], Any] - _is_sse_stream: bool - _stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None - _options: FinalRequestOptions - - http_response: httpx.Response - - retries_taken: int - """The number of retries made. If no retries happened this will be `0`""" - - def __init__( - self, - *, - raw: httpx.Response, - cast_to: type[R], - client: BaseClient[Any, Any], - stream: bool, - stream_cls: type[Stream[Any]] | type[AsyncStream[Any]] | None, - options: FinalRequestOptions, - retries_taken: int = 0, - ) -> None: - self._cast_to = cast_to - self._client = client - self._parsed_by_type = {} - self._is_sse_stream = stream - self._stream_cls = stream_cls - self._options = options - self.http_response = raw - self.retries_taken = retries_taken - - @property - def headers(self) -> httpx.Headers: - return self.http_response.headers - - @property - def http_request(self) -> httpx.Request: - """Returns the httpx Request instance associated with the current response.""" - return self.http_response.request - - @property - def status_code(self) -> int: - return self.http_response.status_code - - @property - def url(self) -> httpx.URL: - """Returns the URL for which the request was made.""" - return self.http_response.url - - @property - def method(self) -> str: - return self.http_request.method - - @property - def http_version(self) -> str: - return self.http_response.http_version - - @property - def elapsed(self) -> datetime.timedelta: - """The time taken for the complete request/response cycle to complete.""" - return self.http_response.elapsed - - @property - def is_closed(self) -> bool: - """Whether or not the response body has been closed. - - If this is False then there is response data that has not been read yet. - You must either fully consume the response body or call `.close()` - before discarding the response to prevent resource leaks. - """ - return self.http_response.is_closed - - @override - def __repr__(self) -> str: - return ( - f"<{self.__class__.__name__} [{self.status_code} {self.http_response.reason_phrase}] type={self._cast_to}>" - ) - - def _parse(self, *, to: type[_T] | None = None) -> R | _T: - cast_to = to if to is not None else self._cast_to - - # unwrap `TypeAlias('Name', T)` -> `T` - if is_type_alias_type(cast_to): - cast_to = cast_to.__value__ # type: ignore[unreachable] - - # unwrap `Annotated[T, ...]` -> `T` - if cast_to and is_annotated_type(cast_to): - cast_to = extract_type_arg(cast_to, 0) - - origin = get_origin(cast_to) or cast_to - - if self._is_sse_stream: - if to: - if not is_stream_class_type(to): - raise TypeError(f"Expected custom parse type to be a subclass of {Stream} or {AsyncStream}") - - return cast( - _T, - to( - cast_to=extract_stream_chunk_type( - to, - failure_message="Expected custom stream type to be passed with a type argument, e.g. Stream[ChunkType]", - ), - response=self.http_response, - client=cast(Any, self._client), - options=self._options, - ), - ) - - if self._stream_cls: - return cast( - R, - self._stream_cls( - cast_to=extract_stream_chunk_type(self._stream_cls), - response=self.http_response, - client=cast(Any, self._client), - options=self._options, - ), - ) - - stream_cls = cast("type[Stream[Any]] | type[AsyncStream[Any]] | None", self._client._default_stream_cls) - if stream_cls is None: - raise MissingStreamClassError() - - return cast( - R, - stream_cls( - cast_to=cast_to, - response=self.http_response, - client=cast(Any, self._client), - options=self._options, - ), - ) - - if cast_to is NoneType: - return cast(R, None) - - response = self.http_response - if cast_to == str: - return cast(R, response.text) - - if cast_to == bytes: - return cast(R, response.content) - - if cast_to == int: - return cast(R, int(response.text)) - - if cast_to == float: - return cast(R, float(response.text)) - - if cast_to == bool: - return cast(R, response.text.lower() == "true") - - if origin == APIResponse: - raise RuntimeError("Unexpected state - cast_to is `APIResponse`") - - if inspect.isclass(origin) and issubclass(origin, httpx.Response): - # Because of the invariance of our ResponseT TypeVar, users can subclass httpx.Response - # and pass that class to our request functions. We cannot change the variance to be either - # covariant or contravariant as that makes our usage of ResponseT illegal. We could construct - # the response class ourselves but that is something that should be supported directly in httpx - # as it would be easy to incorrectly construct the Response object due to the multitude of arguments. - if cast_to != httpx.Response: - raise ValueError(f"Subclasses of httpx.Response cannot be passed to `cast_to`") - return cast(R, response) - - if ( - inspect.isclass( - origin # pyright: ignore[reportUnknownArgumentType] - ) - and not issubclass(origin, BaseModel) - and issubclass(origin, pydantic.BaseModel) - ): - raise TypeError("Pydantic models must subclass our base model type, e.g. `from metronome import BaseModel`") - - if ( - cast_to is not object - and not origin is list - and not origin is dict - and not origin is Union - and not issubclass(origin, BaseModel) - ): - raise RuntimeError( - f"Unsupported type, expected {cast_to} to be a subclass of {BaseModel}, {dict}, {list}, {Union}, {NoneType}, {str} or {httpx.Response}." - ) - - # split is required to handle cases where additional information is included - # in the response, e.g. application/json; charset=utf-8 - content_type, *_ = response.headers.get("content-type", "*").split(";") - if not content_type.endswith("json"): - if is_basemodel(cast_to): - try: - data = response.json() - except Exception as exc: - log.debug("Could not read JSON from response data due to %s - %s", type(exc), exc) - else: - return self._client._process_response_data( - data=data, - cast_to=cast_to, # type: ignore - response=response, - ) - - if self._client._strict_response_validation: - raise APIResponseValidationError( - response=response, - message=f"Expected Content-Type response header to be `application/json` but received `{content_type}` instead.", - body=response.text, - ) - - # If the API responds with content that isn't JSON then we just return - # the (decoded) text without performing any parsing so that you can still - # handle the response however you need to. - return response.text # type: ignore - - data = response.json() - - return self._client._process_response_data( - data=data, - cast_to=cast_to, # type: ignore - response=response, - ) - - -class APIResponse(BaseAPIResponse[R]): - @overload - def parse(self, *, to: type[_T]) -> _T: ... - - @overload - def parse(self) -> R: ... - - def parse(self, *, to: type[_T] | None = None) -> R | _T: - """Returns the rich python representation of this response's data. - - For lower-level control, see `.read()`, `.json()`, `.iter_bytes()`. - - You can customise the type that the response is parsed into through - the `to` argument, e.g. - - ```py - from metronome import BaseModel - - - class MyModel(BaseModel): - foo: str - - - obj = response.parse(to=MyModel) - print(obj.foo) - ``` - - We support parsing: - - `BaseModel` - - `dict` - - `list` - - `Union` - - `str` - - `int` - - `float` - - `httpx.Response` - """ - cache_key = to if to is not None else self._cast_to - cached = self._parsed_by_type.get(cache_key) - if cached is not None: - return cached # type: ignore[no-any-return] - - if not self._is_sse_stream: - self.read() - - parsed = self._parse(to=to) - if is_given(self._options.post_parser): - parsed = self._options.post_parser(parsed) - - self._parsed_by_type[cache_key] = parsed - return parsed - - def read(self) -> bytes: - """Read and return the binary response content.""" - try: - return self.http_response.read() - except httpx.StreamConsumed as exc: - # The default error raised by httpx isn't very - # helpful in our case so we re-raise it with - # a different error message. - raise StreamAlreadyConsumed() from exc - - def text(self) -> str: - """Read and decode the response content into a string.""" - self.read() - return self.http_response.text - - def json(self) -> object: - """Read and decode the JSON response content.""" - self.read() - return self.http_response.json() - - def close(self) -> None: - """Close the response and release the connection. - - Automatically called if the response body is read to completion. - """ - self.http_response.close() - - def iter_bytes(self, chunk_size: int | None = None) -> Iterator[bytes]: - """ - A byte-iterator over the decoded response content. - - This automatically handles gzip, deflate and brotli encoded responses. - """ - for chunk in self.http_response.iter_bytes(chunk_size): - yield chunk - - def iter_text(self, chunk_size: int | None = None) -> Iterator[str]: - """A str-iterator over the decoded response content - that handles both gzip, deflate, etc but also detects the content's - string encoding. - """ - for chunk in self.http_response.iter_text(chunk_size): - yield chunk - - def iter_lines(self) -> Iterator[str]: - """Like `iter_text()` but will only yield chunks for each line""" - for chunk in self.http_response.iter_lines(): - yield chunk - - -class AsyncAPIResponse(BaseAPIResponse[R]): - @overload - async def parse(self, *, to: type[_T]) -> _T: ... - - @overload - async def parse(self) -> R: ... - - async def parse(self, *, to: type[_T] | None = None) -> R | _T: - """Returns the rich python representation of this response's data. - - For lower-level control, see `.read()`, `.json()`, `.iter_bytes()`. - - You can customise the type that the response is parsed into through - the `to` argument, e.g. - - ```py - from metronome import BaseModel - - - class MyModel(BaseModel): - foo: str - - - obj = response.parse(to=MyModel) - print(obj.foo) - ``` - - We support parsing: - - `BaseModel` - - `dict` - - `list` - - `Union` - - `str` - - `httpx.Response` - """ - cache_key = to if to is not None else self._cast_to - cached = self._parsed_by_type.get(cache_key) - if cached is not None: - return cached # type: ignore[no-any-return] - - if not self._is_sse_stream: - await self.read() - - parsed = self._parse(to=to) - if is_given(self._options.post_parser): - parsed = self._options.post_parser(parsed) - - self._parsed_by_type[cache_key] = parsed - return parsed - - async def read(self) -> bytes: - """Read and return the binary response content.""" - try: - return await self.http_response.aread() - except httpx.StreamConsumed as exc: - # the default error raised by httpx isn't very - # helpful in our case so we re-raise it with - # a different error message - raise StreamAlreadyConsumed() from exc - - async def text(self) -> str: - """Read and decode the response content into a string.""" - await self.read() - return self.http_response.text - - async def json(self) -> object: - """Read and decode the JSON response content.""" - await self.read() - return self.http_response.json() - - async def close(self) -> None: - """Close the response and release the connection. - - Automatically called if the response body is read to completion. - """ - await self.http_response.aclose() - - async def iter_bytes(self, chunk_size: int | None = None) -> AsyncIterator[bytes]: - """ - A byte-iterator over the decoded response content. - - This automatically handles gzip, deflate and brotli encoded responses. - """ - async for chunk in self.http_response.aiter_bytes(chunk_size): - yield chunk - - async def iter_text(self, chunk_size: int | None = None) -> AsyncIterator[str]: - """A str-iterator over the decoded response content - that handles both gzip, deflate, etc but also detects the content's - string encoding. - """ - async for chunk in self.http_response.aiter_text(chunk_size): - yield chunk - - async def iter_lines(self) -> AsyncIterator[str]: - """Like `iter_text()` but will only yield chunks for each line""" - async for chunk in self.http_response.aiter_lines(): - yield chunk - - -class BinaryAPIResponse(APIResponse[bytes]): - """Subclass of APIResponse providing helpers for dealing with binary data. - - Note: If you want to stream the response data instead of eagerly reading it - all at once then you should use `.with_streaming_response` when making - the API request, e.g. `.with_streaming_response.get_binary_response()` - """ - - def write_to_file( - self, - file: str | os.PathLike[str], - ) -> None: - """Write the output to the given file. - - Accepts a filename or any path-like object, e.g. pathlib.Path - - Note: if you want to stream the data to the file instead of writing - all at once then you should use `.with_streaming_response` when making - the API request, e.g. `.with_streaming_response.get_binary_response()` - """ - with open(file, mode="wb") as f: - for data in self.iter_bytes(): - f.write(data) - - -class AsyncBinaryAPIResponse(AsyncAPIResponse[bytes]): - """Subclass of APIResponse providing helpers for dealing with binary data. - - Note: If you want to stream the response data instead of eagerly reading it - all at once then you should use `.with_streaming_response` when making - the API request, e.g. `.with_streaming_response.get_binary_response()` - """ - - async def write_to_file( - self, - file: str | os.PathLike[str], - ) -> None: - """Write the output to the given file. - - Accepts a filename or any path-like object, e.g. pathlib.Path - - Note: if you want to stream the data to the file instead of writing - all at once then you should use `.with_streaming_response` when making - the API request, e.g. `.with_streaming_response.get_binary_response()` - """ - path = anyio.Path(file) - async with await path.open(mode="wb") as f: - async for data in self.iter_bytes(): - await f.write(data) - - -class StreamedBinaryAPIResponse(APIResponse[bytes]): - def stream_to_file( - self, - file: str | os.PathLike[str], - *, - chunk_size: int | None = None, - ) -> None: - """Streams the output to the given file. - - Accepts a filename or any path-like object, e.g. pathlib.Path - """ - with open(file, mode="wb") as f: - for data in self.iter_bytes(chunk_size): - f.write(data) - - -class AsyncStreamedBinaryAPIResponse(AsyncAPIResponse[bytes]): - async def stream_to_file( - self, - file: str | os.PathLike[str], - *, - chunk_size: int | None = None, - ) -> None: - """Streams the output to the given file. - - Accepts a filename or any path-like object, e.g. pathlib.Path - """ - path = anyio.Path(file) - async with await path.open(mode="wb") as f: - async for data in self.iter_bytes(chunk_size): - await f.write(data) - - -class MissingStreamClassError(TypeError): - def __init__(self) -> None: - super().__init__( - "The `stream` argument was set to `True` but the `stream_cls` argument was not given. See `metronome._streaming` for reference", - ) - - -class StreamAlreadyConsumed(MetronomeError): - """ - Attempted to read or stream content, but the content has already - been streamed. - - This can happen if you use a method like `.iter_lines()` and then attempt - to read th entire response body afterwards, e.g. - - ```py - response = await client.post(...) - async for line in response.iter_lines(): - ... # do something with `line` - - content = await response.read() - # ^ error - ``` - - If you want this behaviour you'll need to either manually accumulate the response - content or call `await response.read()` before iterating over the stream. - """ - - def __init__(self) -> None: - message = ( - "Attempted to read or stream some content, but the content has " - "already been streamed. " - "This could be due to attempting to stream the response " - "content more than once." - "\n\n" - "You can fix this by manually accumulating the response content while streaming " - "or by calling `.read()` before starting to stream." - ) - super().__init__(message) - - -class ResponseContextManager(Generic[_APIResponseT]): - """Context manager for ensuring that a request is not made - until it is entered and that the response will always be closed - when the context manager exits - """ - - def __init__(self, request_func: Callable[[], _APIResponseT]) -> None: - self._request_func = request_func - self.__response: _APIResponseT | None = None - - def __enter__(self) -> _APIResponseT: - self.__response = self._request_func() - return self.__response - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - if self.__response is not None: - self.__response.close() - - -class AsyncResponseContextManager(Generic[_AsyncAPIResponseT]): - """Context manager for ensuring that a request is not made - until it is entered and that the response will always be closed - when the context manager exits - """ - - def __init__(self, api_request: Awaitable[_AsyncAPIResponseT]) -> None: - self._api_request = api_request - self.__response: _AsyncAPIResponseT | None = None - - async def __aenter__(self) -> _AsyncAPIResponseT: - self.__response = await self._api_request - return self.__response - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - if self.__response is not None: - await self.__response.close() - - -def to_streamed_response_wrapper(func: Callable[P, R]) -> Callable[P, ResponseContextManager[APIResponse[R]]]: - """Higher order function that takes one of our bound API methods and wraps it - to support streaming and returning the raw `APIResponse` object directly. - """ - - @functools.wraps(func) - def wrapped(*args: P.args, **kwargs: P.kwargs) -> ResponseContextManager[APIResponse[R]]: - extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "stream" - - kwargs["extra_headers"] = extra_headers - - make_request = functools.partial(func, *args, **kwargs) - - return ResponseContextManager(cast(Callable[[], APIResponse[R]], make_request)) - - return wrapped - - -def async_to_streamed_response_wrapper( - func: Callable[P, Awaitable[R]], -) -> Callable[P, AsyncResponseContextManager[AsyncAPIResponse[R]]]: - """Higher order function that takes one of our bound API methods and wraps it - to support streaming and returning the raw `APIResponse` object directly. - """ - - @functools.wraps(func) - def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncResponseContextManager[AsyncAPIResponse[R]]: - extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "stream" - - kwargs["extra_headers"] = extra_headers - - make_request = func(*args, **kwargs) - - return AsyncResponseContextManager(cast(Awaitable[AsyncAPIResponse[R]], make_request)) - - return wrapped - - -def to_custom_streamed_response_wrapper( - func: Callable[P, object], - response_cls: type[_APIResponseT], -) -> Callable[P, ResponseContextManager[_APIResponseT]]: - """Higher order function that takes one of our bound API methods and an `APIResponse` class - and wraps the method to support streaming and returning the given response class directly. - - Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` - """ - - @functools.wraps(func) - def wrapped(*args: P.args, **kwargs: P.kwargs) -> ResponseContextManager[_APIResponseT]: - extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "stream" - extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls - - kwargs["extra_headers"] = extra_headers - - make_request = functools.partial(func, *args, **kwargs) - - return ResponseContextManager(cast(Callable[[], _APIResponseT], make_request)) - - return wrapped - - -def async_to_custom_streamed_response_wrapper( - func: Callable[P, Awaitable[object]], - response_cls: type[_AsyncAPIResponseT], -) -> Callable[P, AsyncResponseContextManager[_AsyncAPIResponseT]]: - """Higher order function that takes one of our bound API methods and an `APIResponse` class - and wraps the method to support streaming and returning the given response class directly. - - Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` - """ - - @functools.wraps(func) - def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncResponseContextManager[_AsyncAPIResponseT]: - extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "stream" - extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls - - kwargs["extra_headers"] = extra_headers - - make_request = func(*args, **kwargs) - - return AsyncResponseContextManager(cast(Awaitable[_AsyncAPIResponseT], make_request)) - - return wrapped - - -def to_raw_response_wrapper(func: Callable[P, R]) -> Callable[P, APIResponse[R]]: - """Higher order function that takes one of our bound API methods and wraps it - to support returning the raw `APIResponse` object directly. - """ - - @functools.wraps(func) - def wrapped(*args: P.args, **kwargs: P.kwargs) -> APIResponse[R]: - extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "raw" - - kwargs["extra_headers"] = extra_headers - - return cast(APIResponse[R], func(*args, **kwargs)) - - return wrapped - - -def async_to_raw_response_wrapper(func: Callable[P, Awaitable[R]]) -> Callable[P, Awaitable[AsyncAPIResponse[R]]]: - """Higher order function that takes one of our bound API methods and wraps it - to support returning the raw `APIResponse` object directly. - """ - - @functools.wraps(func) - async def wrapped(*args: P.args, **kwargs: P.kwargs) -> AsyncAPIResponse[R]: - extra_headers: dict[str, str] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "raw" - - kwargs["extra_headers"] = extra_headers - - return cast(AsyncAPIResponse[R], await func(*args, **kwargs)) - - return wrapped - - -def to_custom_raw_response_wrapper( - func: Callable[P, object], - response_cls: type[_APIResponseT], -) -> Callable[P, _APIResponseT]: - """Higher order function that takes one of our bound API methods and an `APIResponse` class - and wraps the method to support returning the given response class directly. - - Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` - """ - - @functools.wraps(func) - def wrapped(*args: P.args, **kwargs: P.kwargs) -> _APIResponseT: - extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "raw" - extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls - - kwargs["extra_headers"] = extra_headers - - return cast(_APIResponseT, func(*args, **kwargs)) - - return wrapped - - -def async_to_custom_raw_response_wrapper( - func: Callable[P, Awaitable[object]], - response_cls: type[_AsyncAPIResponseT], -) -> Callable[P, Awaitable[_AsyncAPIResponseT]]: - """Higher order function that takes one of our bound API methods and an `APIResponse` class - and wraps the method to support returning the given response class directly. - - Note: the given `response_cls` *must* be concrete, e.g. `class BinaryAPIResponse(APIResponse[bytes])` - """ - - @functools.wraps(func) - def wrapped(*args: P.args, **kwargs: P.kwargs) -> Awaitable[_AsyncAPIResponseT]: - extra_headers: dict[str, Any] = {**(cast(Any, kwargs.get("extra_headers")) or {})} - extra_headers[RAW_RESPONSE_HEADER] = "raw" - extra_headers[OVERRIDE_CAST_TO_HEADER] = response_cls - - kwargs["extra_headers"] = extra_headers - - return cast(Awaitable[_AsyncAPIResponseT], func(*args, **kwargs)) - - return wrapped - - -def extract_response_type(typ: type[BaseAPIResponse[Any]]) -> type: - """Given a type like `APIResponse[T]`, returns the generic type variable `T`. - - This also handles the case where a concrete subclass is given, e.g. - ```py - class MyResponse(APIResponse[bytes]): - ... - - extract_response_type(MyResponse) -> bytes - ``` - """ - return extract_type_var_from_base( - typ, - generic_bases=cast("tuple[type, ...]", (BaseAPIResponse, APIResponse, AsyncAPIResponse)), - index=0, - ) diff --git a/src/metronome/_streaming.py b/src/metronome/_streaming.py deleted file mode 100644 index ed4223ef2..000000000 --- a/src/metronome/_streaming.py +++ /dev/null @@ -1,338 +0,0 @@ -# Note: initially copied from https://github.com/florimondmanca/httpx-sse/blob/master/src/httpx_sse/_decoders.py -from __future__ import annotations - -import json -import inspect -from types import TracebackType -from typing import TYPE_CHECKING, Any, Generic, TypeVar, Iterator, Optional, AsyncIterator, cast -from typing_extensions import Self, Protocol, TypeGuard, override, get_origin, runtime_checkable - -import httpx - -from ._utils import extract_type_var_from_base - -if TYPE_CHECKING: - from ._client import Metronome, AsyncMetronome - from ._models import FinalRequestOptions - - -_T = TypeVar("_T") - - -class Stream(Generic[_T]): - """Provides the core interface to iterate over a synchronous stream response.""" - - response: httpx.Response - _options: Optional[FinalRequestOptions] = None - _decoder: SSEBytesDecoder - - def __init__( - self, - *, - cast_to: type[_T], - response: httpx.Response, - client: Metronome, - options: Optional[FinalRequestOptions] = None, - ) -> None: - self.response = response - self._cast_to = cast_to - self._client = client - self._options = options - self._decoder = client._make_sse_decoder() - self._iterator = self.__stream__() - - def __next__(self) -> _T: - return self._iterator.__next__() - - def __iter__(self) -> Iterator[_T]: - for item in self._iterator: - yield item - - def _iter_events(self) -> Iterator[ServerSentEvent]: - yield from self._decoder.iter_bytes(self.response.iter_bytes()) - - def __stream__(self) -> Iterator[_T]: - cast_to = cast(Any, self._cast_to) - response = self.response - process_data = self._client._process_response_data - iterator = self._iter_events() - - try: - for sse in iterator: - yield process_data(data=sse.json(), cast_to=cast_to, response=response) - finally: - # Ensure the response is closed even if the consumer doesn't read all data - response.close() - - def __enter__(self) -> Self: - return self - - def __exit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - self.close() - - def close(self) -> None: - """ - Close the response and release the connection. - - Automatically called if the response body is read to completion. - """ - self.response.close() - - -class AsyncStream(Generic[_T]): - """Provides the core interface to iterate over an asynchronous stream response.""" - - response: httpx.Response - _options: Optional[FinalRequestOptions] = None - _decoder: SSEDecoder | SSEBytesDecoder - - def __init__( - self, - *, - cast_to: type[_T], - response: httpx.Response, - client: AsyncMetronome, - options: Optional[FinalRequestOptions] = None, - ) -> None: - self.response = response - self._cast_to = cast_to - self._client = client - self._options = options - self._decoder = client._make_sse_decoder() - self._iterator = self.__stream__() - - async def __anext__(self) -> _T: - return await self._iterator.__anext__() - - async def __aiter__(self) -> AsyncIterator[_T]: - async for item in self._iterator: - yield item - - async def _iter_events(self) -> AsyncIterator[ServerSentEvent]: - async for sse in self._decoder.aiter_bytes(self.response.aiter_bytes()): - yield sse - - async def __stream__(self) -> AsyncIterator[_T]: - cast_to = cast(Any, self._cast_to) - response = self.response - process_data = self._client._process_response_data - iterator = self._iter_events() - - try: - async for sse in iterator: - yield process_data(data=sse.json(), cast_to=cast_to, response=response) - finally: - # Ensure the response is closed even if the consumer doesn't read all data - await response.aclose() - - async def __aenter__(self) -> Self: - return self - - async def __aexit__( - self, - exc_type: type[BaseException] | None, - exc: BaseException | None, - exc_tb: TracebackType | None, - ) -> None: - await self.close() - - async def close(self) -> None: - """ - Close the response and release the connection. - - Automatically called if the response body is read to completion. - """ - await self.response.aclose() - - -class ServerSentEvent: - def __init__( - self, - *, - event: str | None = None, - data: str | None = None, - id: str | None = None, - retry: int | None = None, - ) -> None: - if data is None: - data = "" - - self._id = id - self._data = data - self._event = event or None - self._retry = retry - - @property - def event(self) -> str | None: - return self._event - - @property - def id(self) -> str | None: - return self._id - - @property - def retry(self) -> int | None: - return self._retry - - @property - def data(self) -> str: - return self._data - - def json(self) -> Any: - return json.loads(self.data) - - @override - def __repr__(self) -> str: - return f"ServerSentEvent(event={self.event}, data={self.data}, id={self.id}, retry={self.retry})" - - -class SSEDecoder: - _data: list[str] - _event: str | None - _retry: int | None - _last_event_id: str | None - - def __init__(self) -> None: - self._event = None - self._data = [] - self._last_event_id = None - self._retry = None - - def iter_bytes(self, iterator: Iterator[bytes]) -> Iterator[ServerSentEvent]: - """Given an iterator that yields raw binary data, iterate over it & yield every event encountered""" - for chunk in self._iter_chunks(iterator): - # Split before decoding so splitlines() only uses \r and \n - for raw_line in chunk.splitlines(): - line = raw_line.decode("utf-8") - sse = self.decode(line) - if sse: - yield sse - - def _iter_chunks(self, iterator: Iterator[bytes]) -> Iterator[bytes]: - """Given an iterator that yields raw binary data, iterate over it and yield individual SSE chunks""" - data = b"" - for chunk in iterator: - for line in chunk.splitlines(keepends=True): - data += line - if data.endswith((b"\r\r", b"\n\n", b"\r\n\r\n")): - yield data - data = b"" - if data: - yield data - - async def aiter_bytes(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[ServerSentEvent]: - """Given an iterator that yields raw binary data, iterate over it & yield every event encountered""" - async for chunk in self._aiter_chunks(iterator): - # Split before decoding so splitlines() only uses \r and \n - for raw_line in chunk.splitlines(): - line = raw_line.decode("utf-8") - sse = self.decode(line) - if sse: - yield sse - - async def _aiter_chunks(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[bytes]: - """Given an iterator that yields raw binary data, iterate over it and yield individual SSE chunks""" - data = b"" - async for chunk in iterator: - for line in chunk.splitlines(keepends=True): - data += line - if data.endswith((b"\r\r", b"\n\n", b"\r\n\r\n")): - yield data - data = b"" - if data: - yield data - - def decode(self, line: str) -> ServerSentEvent | None: - # See: https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation # noqa: E501 - - if not line: - if not self._event and not self._data and not self._last_event_id and self._retry is None: - return None - - sse = ServerSentEvent( - event=self._event, - data="\n".join(self._data), - id=self._last_event_id, - retry=self._retry, - ) - - # NOTE: as per the SSE spec, do not reset last_event_id. - self._event = None - self._data = [] - self._retry = None - - return sse - - if line.startswith(":"): - return None - - fieldname, _, value = line.partition(":") - - if value.startswith(" "): - value = value[1:] - - if fieldname == "event": - self._event = value - elif fieldname == "data": - self._data.append(value) - elif fieldname == "id": - if "\0" in value: - pass - else: - self._last_event_id = value - elif fieldname == "retry": - try: - self._retry = int(value) - except (TypeError, ValueError): - pass - else: - pass # Field is ignored. - - return None - - -@runtime_checkable -class SSEBytesDecoder(Protocol): - def iter_bytes(self, iterator: Iterator[bytes]) -> Iterator[ServerSentEvent]: - """Given an iterator that yields raw binary data, iterate over it & yield every event encountered""" - ... - - def aiter_bytes(self, iterator: AsyncIterator[bytes]) -> AsyncIterator[ServerSentEvent]: - """Given an async iterator that yields raw binary data, iterate over it & yield every event encountered""" - ... - - -def is_stream_class_type(typ: type) -> TypeGuard[type[Stream[object]] | type[AsyncStream[object]]]: - """TypeGuard for determining whether or not the given type is a subclass of `Stream` / `AsyncStream`""" - origin = get_origin(typ) or typ - return inspect.isclass(origin) and issubclass(origin, (Stream, AsyncStream)) - - -def extract_stream_chunk_type( - stream_cls: type, - *, - failure_message: str | None = None, -) -> type: - """Given a type like `Stream[T]`, returns the generic type variable `T`. - - This also handles the case where a concrete subclass is given, e.g. - ```py - class MyStream(Stream[bytes]): - ... - - extract_stream_chunk_type(MyStream) -> bytes - ``` - """ - from ._base_client import Stream, AsyncStream - - return extract_type_var_from_base( - stream_cls, - index=0, - generic_bases=cast("tuple[type, ...]", (Stream, AsyncStream)), - failure_message=failure_message, - ) diff --git a/src/metronome/_types.py b/src/metronome/_types.py deleted file mode 100644 index 46822526a..000000000 --- a/src/metronome/_types.py +++ /dev/null @@ -1,270 +0,0 @@ -from __future__ import annotations - -from os import PathLike -from typing import ( - IO, - TYPE_CHECKING, - Any, - Dict, - List, - Type, - Tuple, - Union, - Mapping, - TypeVar, - Callable, - Iterable, - Iterator, - Optional, - Sequence, - AsyncIterable, -) -from typing_extensions import ( - Set, - Literal, - Protocol, - TypeAlias, - TypedDict, - SupportsIndex, - overload, - override, - runtime_checkable, -) - -import httpx -import pydantic -from httpx import URL, Proxy, Timeout, Response, BaseTransport, AsyncBaseTransport - -if TYPE_CHECKING: - from ._models import BaseModel - from ._response import APIResponse, AsyncAPIResponse - -Transport = BaseTransport -AsyncTransport = AsyncBaseTransport -Query = Mapping[str, object] -Body = object -AnyMapping = Mapping[str, object] -ModelT = TypeVar("ModelT", bound=pydantic.BaseModel) -_T = TypeVar("_T") - - -# Approximates httpx internal ProxiesTypes and RequestFiles types -# while adding support for `PathLike` instances -ProxiesDict = Dict["str | URL", Union[None, str, URL, Proxy]] -ProxiesTypes = Union[str, Proxy, ProxiesDict] -if TYPE_CHECKING: - Base64FileInput = Union[IO[bytes], PathLike[str]] - FileContent = Union[IO[bytes], bytes, PathLike[str]] -else: - Base64FileInput = Union[IO[bytes], PathLike] - FileContent = Union[IO[bytes], bytes, PathLike] # PathLike is not subscriptable in Python 3.8. - - -# Used for sending raw binary data / streaming data in request bodies -# e.g. for file uploads without multipart encoding -BinaryTypes = Union[bytes, bytearray, IO[bytes], Iterable[bytes]] -AsyncBinaryTypes = Union[bytes, bytearray, IO[bytes], AsyncIterable[bytes]] - -FileTypes = Union[ - # file (or bytes) - FileContent, - # (filename, file (or bytes)) - Tuple[Optional[str], FileContent], - # (filename, file (or bytes), content_type) - Tuple[Optional[str], FileContent, Optional[str]], - # (filename, file (or bytes), content_type, headers) - Tuple[Optional[str], FileContent, Optional[str], Mapping[str, str]], -] -RequestFiles = Union[Mapping[str, FileTypes], Sequence[Tuple[str, FileTypes]]] - -# duplicate of the above but without our custom file support -HttpxFileContent = Union[IO[bytes], bytes] -HttpxFileTypes = Union[ - # file (or bytes) - HttpxFileContent, - # (filename, file (or bytes)) - Tuple[Optional[str], HttpxFileContent], - # (filename, file (or bytes), content_type) - Tuple[Optional[str], HttpxFileContent, Optional[str]], - # (filename, file (or bytes), content_type, headers) - Tuple[Optional[str], HttpxFileContent, Optional[str], Mapping[str, str]], -] -HttpxRequestFiles = Union[Mapping[str, HttpxFileTypes], Sequence[Tuple[str, HttpxFileTypes]]] - -# Workaround to support (cast_to: Type[ResponseT]) -> ResponseT -# where ResponseT includes `None`. In order to support directly -# passing `None`, overloads would have to be defined for every -# method that uses `ResponseT` which would lead to an unacceptable -# amount of code duplication and make it unreadable. See _base_client.py -# for example usage. -# -# This unfortunately means that you will either have -# to import this type and pass it explicitly: -# -# from metronome import NoneType -# client.get('/foo', cast_to=NoneType) -# -# or build it yourself: -# -# client.get('/foo', cast_to=type(None)) -if TYPE_CHECKING: - NoneType: Type[None] -else: - NoneType = type(None) - - -class RequestOptions(TypedDict, total=False): - headers: Headers - max_retries: int - timeout: float | Timeout | None - params: Query - extra_json: AnyMapping - idempotency_key: str - follow_redirects: bool - - -# Sentinel class used until PEP 0661 is accepted -class NotGiven: - """ - For parameters with a meaningful None value, we need to distinguish between - the user explicitly passing None, and the user not passing the parameter at - all. - - User code shouldn't need to use not_given directly. - - For example: - - ```py - def create(timeout: Timeout | None | NotGiven = not_given): ... - - - create(timeout=1) # 1s timeout - create(timeout=None) # No timeout - create() # Default timeout behavior - ``` - """ - - def __bool__(self) -> Literal[False]: - return False - - @override - def __repr__(self) -> str: - return "NOT_GIVEN" - - -not_given = NotGiven() -# for backwards compatibility: -NOT_GIVEN = NotGiven() - - -class Omit: - """ - To explicitly omit something from being sent in a request, use `omit`. - - ```py - # as the default `Content-Type` header is `application/json` that will be sent - client.post("/upload/files", files={"file": b"my raw file content"}) - - # you can't explicitly override the header as it has to be dynamically generated - # to look something like: 'multipart/form-data; boundary=0d8382fcf5f8c3be01ca2e11002d2983' - client.post(..., headers={"Content-Type": "multipart/form-data"}) - - # instead you can remove the default `application/json` header by passing omit - client.post(..., headers={"Content-Type": omit}) - ``` - """ - - def __bool__(self) -> Literal[False]: - return False - - -omit = Omit() - - -@runtime_checkable -class ModelBuilderProtocol(Protocol): - @classmethod - def build( - cls: type[_T], - *, - response: Response, - data: object, - ) -> _T: ... - - -Headers = Mapping[str, Union[str, Omit]] - - -class HeadersLikeProtocol(Protocol): - def get(self, __key: str) -> str | None: ... - - -HeadersLike = Union[Headers, HeadersLikeProtocol] - -ResponseT = TypeVar( - "ResponseT", - bound=Union[ - object, - str, - None, - "BaseModel", - List[Any], - Dict[str, Any], - Response, - ModelBuilderProtocol, - "APIResponse[Any]", - "AsyncAPIResponse[Any]", - ], -) - -StrBytesIntFloat = Union[str, bytes, int, float] - -# Note: copied from Pydantic -# https://github.com/pydantic/pydantic/blob/6f31f8f68ef011f84357330186f603ff295312fd/pydantic/main.py#L79 -IncEx: TypeAlias = Union[Set[int], Set[str], Mapping[int, Union["IncEx", bool]], Mapping[str, Union["IncEx", bool]]] - -PostParser = Callable[[Any], Any] - - -@runtime_checkable -class InheritsGeneric(Protocol): - """Represents a type that has inherited from `Generic` - - The `__orig_bases__` property can be used to determine the resolved - type variable for a given base class. - """ - - __orig_bases__: tuple[_GenericAlias] - - -class _GenericAlias(Protocol): - __origin__: type[object] - - -class HttpxSendArgs(TypedDict, total=False): - auth: httpx.Auth - follow_redirects: bool - - -_T_co = TypeVar("_T_co", covariant=True) - - -if TYPE_CHECKING: - # This works because str.__contains__ does not accept object (either in typeshed or at runtime) - # https://github.com/hauntsaninja/useful_types/blob/5e9710f3875107d068e7679fd7fec9cfab0eff3b/useful_types/__init__.py#L285 - # - # Note: index() and count() methods are intentionally omitted to allow pyright to properly - # infer TypedDict types when dict literals are used in lists assigned to SequenceNotStr. - class SequenceNotStr(Protocol[_T_co]): - @overload - def __getitem__(self, index: SupportsIndex, /) -> _T_co: ... - @overload - def __getitem__(self, index: slice, /) -> Sequence[_T_co]: ... - def __contains__(self, value: object, /) -> bool: ... - def __len__(self) -> int: ... - def __iter__(self) -> Iterator[_T_co]: ... - def __reversed__(self) -> Iterator[_T_co]: ... -else: - # just point this to a normal `Sequence` at runtime to avoid having to special case - # deserializing our custom sequence type - SequenceNotStr = Sequence diff --git a/src/metronome/_utils/__init__.py b/src/metronome/_utils/__init__.py deleted file mode 100644 index dc64e29a1..000000000 --- a/src/metronome/_utils/__init__.py +++ /dev/null @@ -1,64 +0,0 @@ -from ._sync import asyncify as asyncify -from ._proxy import LazyProxy as LazyProxy -from ._utils import ( - flatten as flatten, - is_dict as is_dict, - is_list as is_list, - is_given as is_given, - is_tuple as is_tuple, - json_safe as json_safe, - lru_cache as lru_cache, - is_mapping as is_mapping, - is_tuple_t as is_tuple_t, - is_iterable as is_iterable, - is_sequence as is_sequence, - coerce_float as coerce_float, - is_mapping_t as is_mapping_t, - removeprefix as removeprefix, - removesuffix as removesuffix, - extract_files as extract_files, - is_sequence_t as is_sequence_t, - required_args as required_args, - coerce_boolean as coerce_boolean, - coerce_integer as coerce_integer, - file_from_path as file_from_path, - strip_not_given as strip_not_given, - deepcopy_minimal as deepcopy_minimal, - get_async_library as get_async_library, - maybe_coerce_float as maybe_coerce_float, - get_required_header as get_required_header, - maybe_coerce_boolean as maybe_coerce_boolean, - maybe_coerce_integer as maybe_coerce_integer, -) -from ._compat import ( - get_args as get_args, - is_union as is_union, - get_origin as get_origin, - is_typeddict as is_typeddict, - is_literal_type as is_literal_type, -) -from ._typing import ( - is_list_type as is_list_type, - is_union_type as is_union_type, - extract_type_arg as extract_type_arg, - is_iterable_type as is_iterable_type, - is_required_type as is_required_type, - is_sequence_type as is_sequence_type, - is_annotated_type as is_annotated_type, - is_type_alias_type as is_type_alias_type, - strip_annotated_type as strip_annotated_type, - extract_type_var_from_base as extract_type_var_from_base, -) -from ._streams import consume_sync_iterator as consume_sync_iterator, consume_async_iterator as consume_async_iterator -from ._transform import ( - PropertyInfo as PropertyInfo, - transform as transform, - async_transform as async_transform, - maybe_transform as maybe_transform, - async_maybe_transform as async_maybe_transform, -) -from ._reflection import ( - function_has_argument as function_has_argument, - assert_signatures_in_sync as assert_signatures_in_sync, -) -from ._datetime_parse import parse_date as parse_date, parse_datetime as parse_datetime diff --git a/src/metronome/_utils/_compat.py b/src/metronome/_utils/_compat.py deleted file mode 100644 index 2c70b299c..000000000 --- a/src/metronome/_utils/_compat.py +++ /dev/null @@ -1,45 +0,0 @@ -from __future__ import annotations - -import sys -import typing_extensions -from typing import Any, Type, Union, Literal, Optional -from datetime import date, datetime -from typing_extensions import get_args as _get_args, get_origin as _get_origin - -from .._types import StrBytesIntFloat -from ._datetime_parse import parse_date as _parse_date, parse_datetime as _parse_datetime - -_LITERAL_TYPES = {Literal, typing_extensions.Literal} - - -def get_args(tp: type[Any]) -> tuple[Any, ...]: - return _get_args(tp) - - -def get_origin(tp: type[Any]) -> type[Any] | None: - return _get_origin(tp) - - -def is_union(tp: Optional[Type[Any]]) -> bool: - if sys.version_info < (3, 10): - return tp is Union # type: ignore[comparison-overlap] - else: - import types - - return tp is Union or tp is types.UnionType # type: ignore[comparison-overlap] - - -def is_typeddict(tp: Type[Any]) -> bool: - return typing_extensions.is_typeddict(tp) - - -def is_literal_type(tp: Type[Any]) -> bool: - return get_origin(tp) in _LITERAL_TYPES - - -def parse_date(value: Union[date, StrBytesIntFloat]) -> date: - return _parse_date(value) - - -def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: - return _parse_datetime(value) diff --git a/src/metronome/_utils/_datetime_parse.py b/src/metronome/_utils/_datetime_parse.py deleted file mode 100644 index 7cb9d9e66..000000000 --- a/src/metronome/_utils/_datetime_parse.py +++ /dev/null @@ -1,136 +0,0 @@ -""" -This file contains code from https://github.com/pydantic/pydantic/blob/main/pydantic/v1/datetime_parse.py -without the Pydantic v1 specific errors. -""" - -from __future__ import annotations - -import re -from typing import Dict, Union, Optional -from datetime import date, datetime, timezone, timedelta - -from .._types import StrBytesIntFloat - -date_expr = r"(?P\d{4})-(?P\d{1,2})-(?P\d{1,2})" -time_expr = ( - r"(?P\d{1,2}):(?P\d{1,2})" - r"(?::(?P\d{1,2})(?:\.(?P\d{1,6})\d{0,6})?)?" - r"(?PZ|[+-]\d{2}(?::?\d{2})?)?$" -) - -date_re = re.compile(f"{date_expr}$") -datetime_re = re.compile(f"{date_expr}[T ]{time_expr}") - - -EPOCH = datetime(1970, 1, 1) -# if greater than this, the number is in ms, if less than or equal it's in seconds -# (in seconds this is 11th October 2603, in ms it's 20th August 1970) -MS_WATERSHED = int(2e10) -# slightly more than datetime.max in ns - (datetime.max - EPOCH).total_seconds() * 1e9 -MAX_NUMBER = int(3e20) - - -def _get_numeric(value: StrBytesIntFloat, native_expected_type: str) -> Union[None, int, float]: - if isinstance(value, (int, float)): - return value - try: - return float(value) - except ValueError: - return None - except TypeError: - raise TypeError(f"invalid type; expected {native_expected_type}, string, bytes, int or float") from None - - -def _from_unix_seconds(seconds: Union[int, float]) -> datetime: - if seconds > MAX_NUMBER: - return datetime.max - elif seconds < -MAX_NUMBER: - return datetime.min - - while abs(seconds) > MS_WATERSHED: - seconds /= 1000 - dt = EPOCH + timedelta(seconds=seconds) - return dt.replace(tzinfo=timezone.utc) - - -def _parse_timezone(value: Optional[str]) -> Union[None, int, timezone]: - if value == "Z": - return timezone.utc - elif value is not None: - offset_mins = int(value[-2:]) if len(value) > 3 else 0 - offset = 60 * int(value[1:3]) + offset_mins - if value[0] == "-": - offset = -offset - return timezone(timedelta(minutes=offset)) - else: - return None - - -def parse_datetime(value: Union[datetime, StrBytesIntFloat]) -> datetime: - """ - Parse a datetime/int/float/string and return a datetime.datetime. - - This function supports time zone offsets. When the input contains one, - the output uses a timezone with a fixed offset from UTC. - - Raise ValueError if the input is well formatted but not a valid datetime. - Raise ValueError if the input isn't well formatted. - """ - if isinstance(value, datetime): - return value - - number = _get_numeric(value, "datetime") - if number is not None: - return _from_unix_seconds(number) - - if isinstance(value, bytes): - value = value.decode() - - assert not isinstance(value, (float, int)) - - match = datetime_re.match(value) - if match is None: - raise ValueError("invalid datetime format") - - kw = match.groupdict() - if kw["microsecond"]: - kw["microsecond"] = kw["microsecond"].ljust(6, "0") - - tzinfo = _parse_timezone(kw.pop("tzinfo")) - kw_: Dict[str, Union[None, int, timezone]] = {k: int(v) for k, v in kw.items() if v is not None} - kw_["tzinfo"] = tzinfo - - return datetime(**kw_) # type: ignore - - -def parse_date(value: Union[date, StrBytesIntFloat]) -> date: - """ - Parse a date/int/float/string and return a datetime.date. - - Raise ValueError if the input is well formatted but not a valid date. - Raise ValueError if the input isn't well formatted. - """ - if isinstance(value, date): - if isinstance(value, datetime): - return value.date() - else: - return value - - number = _get_numeric(value, "date") - if number is not None: - return _from_unix_seconds(number).date() - - if isinstance(value, bytes): - value = value.decode() - - assert not isinstance(value, (float, int)) - match = date_re.match(value) - if match is None: - raise ValueError("invalid date format") - - kw = {k: int(v) for k, v in match.groupdict().items()} - - try: - return date(**kw) - except ValueError: - raise ValueError("invalid date format") from None diff --git a/src/metronome/_utils/_json.py b/src/metronome/_utils/_json.py deleted file mode 100644 index 60584214a..000000000 --- a/src/metronome/_utils/_json.py +++ /dev/null @@ -1,35 +0,0 @@ -import json -from typing import Any -from datetime import datetime -from typing_extensions import override - -import pydantic - -from .._compat import model_dump - - -def openapi_dumps(obj: Any) -> bytes: - """ - Serialize an object to UTF-8 encoded JSON bytes. - - Extends the standard json.dumps with support for additional types - commonly used in the SDK, such as `datetime`, `pydantic.BaseModel`, etc. - """ - return json.dumps( - obj, - cls=_CustomEncoder, - # Uses the same defaults as httpx's JSON serialization - ensure_ascii=False, - separators=(",", ":"), - allow_nan=False, - ).encode() - - -class _CustomEncoder(json.JSONEncoder): - @override - def default(self, o: Any) -> Any: - if isinstance(o, datetime): - return o.isoformat() - if isinstance(o, pydantic.BaseModel): - return model_dump(o, exclude_unset=True, mode="json", by_alias=True) - return super().default(o) diff --git a/src/metronome/_utils/_logs.py b/src/metronome/_utils/_logs.py deleted file mode 100644 index 4860a95b8..000000000 --- a/src/metronome/_utils/_logs.py +++ /dev/null @@ -1,25 +0,0 @@ -import os -import logging - -logger: logging.Logger = logging.getLogger("metronome") -httpx_logger: logging.Logger = logging.getLogger("httpx") - - -def _basic_config() -> None: - # e.g. [2023-10-05 14:12:26 - metronome._base_client:818 - DEBUG] HTTP Request: POST http://127.0.0.1:4010/foo/bar "200 OK" - logging.basicConfig( - format="[%(asctime)s - %(name)s:%(lineno)d - %(levelname)s] %(message)s", - datefmt="%Y-%m-%d %H:%M:%S", - ) - - -def setup_logging() -> None: - env = os.environ.get("METRONOME_LOG") - if env == "debug": - _basic_config() - logger.setLevel(logging.DEBUG) - httpx_logger.setLevel(logging.DEBUG) - elif env == "info": - _basic_config() - logger.setLevel(logging.INFO) - httpx_logger.setLevel(logging.INFO) diff --git a/src/metronome/_utils/_proxy.py b/src/metronome/_utils/_proxy.py deleted file mode 100644 index 0f239a33c..000000000 --- a/src/metronome/_utils/_proxy.py +++ /dev/null @@ -1,65 +0,0 @@ -from __future__ import annotations - -from abc import ABC, abstractmethod -from typing import Generic, TypeVar, Iterable, cast -from typing_extensions import override - -T = TypeVar("T") - - -class LazyProxy(Generic[T], ABC): - """Implements data methods to pretend that an instance is another instance. - - This includes forwarding attribute access and other methods. - """ - - # Note: we have to special case proxies that themselves return proxies - # to support using a proxy as a catch-all for any random access, e.g. `proxy.foo.bar.baz` - - def __getattr__(self, attr: str) -> object: - proxied = self.__get_proxied__() - if isinstance(proxied, LazyProxy): - return proxied # pyright: ignore - return getattr(proxied, attr) - - @override - def __repr__(self) -> str: - proxied = self.__get_proxied__() - if isinstance(proxied, LazyProxy): - return proxied.__class__.__name__ - return repr(self.__get_proxied__()) - - @override - def __str__(self) -> str: - proxied = self.__get_proxied__() - if isinstance(proxied, LazyProxy): - return proxied.__class__.__name__ - return str(proxied) - - @override - def __dir__(self) -> Iterable[str]: - proxied = self.__get_proxied__() - if isinstance(proxied, LazyProxy): - return [] - return proxied.__dir__() - - @property # type: ignore - @override - def __class__(self) -> type: # pyright: ignore - try: - proxied = self.__get_proxied__() - except Exception: - return type(self) - if issubclass(type(proxied), LazyProxy): - return type(proxied) - return proxied.__class__ - - def __get_proxied__(self) -> T: - return self.__load__() - - def __as_proxied__(self) -> T: - """Helper method that returns the current proxy, typed as the loaded object""" - return cast(T, self) - - @abstractmethod - def __load__(self) -> T: ... diff --git a/src/metronome/_utils/_reflection.py b/src/metronome/_utils/_reflection.py deleted file mode 100644 index 89aa712ac..000000000 --- a/src/metronome/_utils/_reflection.py +++ /dev/null @@ -1,42 +0,0 @@ -from __future__ import annotations - -import inspect -from typing import Any, Callable - - -def function_has_argument(func: Callable[..., Any], arg_name: str) -> bool: - """Returns whether or not the given function has a specific parameter""" - sig = inspect.signature(func) - return arg_name in sig.parameters - - -def assert_signatures_in_sync( - source_func: Callable[..., Any], - check_func: Callable[..., Any], - *, - exclude_params: set[str] = set(), -) -> None: - """Ensure that the signature of the second function matches the first.""" - - check_sig = inspect.signature(check_func) - source_sig = inspect.signature(source_func) - - errors: list[str] = [] - - for name, source_param in source_sig.parameters.items(): - if name in exclude_params: - continue - - custom_param = check_sig.parameters.get(name) - if not custom_param: - errors.append(f"the `{name}` param is missing") - continue - - if custom_param.annotation != source_param.annotation: - errors.append( - f"types for the `{name}` param are do not match; source={repr(source_param.annotation)} checking={repr(custom_param.annotation)}" - ) - continue - - if errors: - raise AssertionError(f"{len(errors)} errors encountered when comparing signatures:\n\n" + "\n\n".join(errors)) diff --git a/src/metronome/_utils/_resources_proxy.py b/src/metronome/_utils/_resources_proxy.py deleted file mode 100644 index 6956e52f5..000000000 --- a/src/metronome/_utils/_resources_proxy.py +++ /dev/null @@ -1,24 +0,0 @@ -from __future__ import annotations - -from typing import Any -from typing_extensions import override - -from ._proxy import LazyProxy - - -class ResourcesProxy(LazyProxy[Any]): - """A proxy for the `metronome.resources` module. - - This is used so that we can lazily import `metronome.resources` only when - needed *and* so that users can just import `metronome` and reference `metronome.resources` - """ - - @override - def __load__(self) -> Any: - import importlib - - mod = importlib.import_module("metronome.resources") - return mod - - -resources = ResourcesProxy().__as_proxied__() diff --git a/src/metronome/_utils/_streams.py b/src/metronome/_utils/_streams.py deleted file mode 100644 index f4a0208f0..000000000 --- a/src/metronome/_utils/_streams.py +++ /dev/null @@ -1,12 +0,0 @@ -from typing import Any -from typing_extensions import Iterator, AsyncIterator - - -def consume_sync_iterator(iterator: Iterator[Any]) -> None: - for _ in iterator: - ... - - -async def consume_async_iterator(iterator: AsyncIterator[Any]) -> None: - async for _ in iterator: - ... diff --git a/src/metronome/_utils/_sync.py b/src/metronome/_utils/_sync.py deleted file mode 100644 index f6027c183..000000000 --- a/src/metronome/_utils/_sync.py +++ /dev/null @@ -1,58 +0,0 @@ -from __future__ import annotations - -import asyncio -import functools -from typing import TypeVar, Callable, Awaitable -from typing_extensions import ParamSpec - -import anyio -import sniffio -import anyio.to_thread - -T_Retval = TypeVar("T_Retval") -T_ParamSpec = ParamSpec("T_ParamSpec") - - -async def to_thread( - func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs -) -> T_Retval: - if sniffio.current_async_library() == "asyncio": - return await asyncio.to_thread(func, *args, **kwargs) - - return await anyio.to_thread.run_sync( - functools.partial(func, *args, **kwargs), - ) - - -# inspired by `asyncer`, https://github.com/tiangolo/asyncer -def asyncify(function: Callable[T_ParamSpec, T_Retval]) -> Callable[T_ParamSpec, Awaitable[T_Retval]]: - """ - Take a blocking function and create an async one that receives the same - positional and keyword arguments. - - Usage: - - ```python - def blocking_func(arg1, arg2, kwarg1=None): - # blocking code - return result - - - result = asyncify(blocking_function)(arg1, arg2, kwarg1=value1) - ``` - - ## Arguments - - `function`: a blocking regular callable (e.g. a function) - - ## Return - - An async function that takes the same positional and keyword arguments as the - original one, that when called runs the same original function in a thread worker - and returns the result. - """ - - async def wrapper(*args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs) -> T_Retval: - return await to_thread(function, *args, **kwargs) - - return wrapper diff --git a/src/metronome/_utils/_transform.py b/src/metronome/_utils/_transform.py deleted file mode 100644 index 35eafd29a..000000000 --- a/src/metronome/_utils/_transform.py +++ /dev/null @@ -1,463 +0,0 @@ -from __future__ import annotations - -import io -import base64 -import pathlib -from typing import Any, Mapping, TypeVar, cast -from datetime import date, datetime -from typing_extensions import Literal, get_args, override, get_type_hints as _get_type_hints - -import anyio -import pydantic - -from ._utils import ( - is_list, - is_given, - lru_cache, - is_mapping, - is_iterable, - is_sequence, -) -from .._files import is_base64_file_input -from ._compat import get_origin, is_typeddict -from ._typing import ( - is_list_type, - is_union_type, - extract_type_arg, - is_iterable_type, - is_required_type, - is_sequence_type, - is_annotated_type, - strip_annotated_type, -) - -_T = TypeVar("_T") - - -# TODO: support for drilling globals() and locals() -# TODO: ensure works correctly with forward references in all cases - - -PropertyFormat = Literal["iso8601", "base64", "custom"] - - -class PropertyInfo: - """Metadata class to be used in Annotated types to provide information about a given type. - - For example: - - class MyParams(TypedDict): - account_holder_name: Annotated[str, PropertyInfo(alias='accountHolderName')] - - This means that {'account_holder_name': 'Robert'} will be transformed to {'accountHolderName': 'Robert'} before being sent to the API. - """ - - alias: str | None - format: PropertyFormat | None - format_template: str | None - discriminator: str | None - - def __init__( - self, - *, - alias: str | None = None, - format: PropertyFormat | None = None, - format_template: str | None = None, - discriminator: str | None = None, - ) -> None: - self.alias = alias - self.format = format - self.format_template = format_template - self.discriminator = discriminator - - @override - def __repr__(self) -> str: - return f"{self.__class__.__name__}(alias='{self.alias}', format={self.format}, format_template='{self.format_template}', discriminator='{self.discriminator}')" - - -def maybe_transform( - data: object, - expected_type: object, -) -> Any | None: - """Wrapper over `transform()` that allows `None` to be passed. - - See `transform()` for more details. - """ - if data is None: - return None - return transform(data, expected_type) - - -# Wrapper over _transform_recursive providing fake types -def transform( - data: _T, - expected_type: object, -) -> _T: - """Transform dictionaries based off of type information from the given type, for example: - - ```py - class Params(TypedDict, total=False): - card_id: Required[Annotated[str, PropertyInfo(alias="cardID")]] - - - transformed = transform({"card_id": ""}, Params) - # {'cardID': ''} - ``` - - Any keys / data that does not have type information given will be included as is. - - It should be noted that the transformations that this function does are not represented in the type system. - """ - transformed = _transform_recursive(data, annotation=cast(type, expected_type)) - return cast(_T, transformed) - - -@lru_cache(maxsize=8096) -def _get_annotated_type(type_: type) -> type | None: - """If the given type is an `Annotated` type then it is returned, if not `None` is returned. - - This also unwraps the type when applicable, e.g. `Required[Annotated[T, ...]]` - """ - if is_required_type(type_): - # Unwrap `Required[Annotated[T, ...]]` to `Annotated[T, ...]` - type_ = get_args(type_)[0] - - if is_annotated_type(type_): - return type_ - - return None - - -def _maybe_transform_key(key: str, type_: type) -> str: - """Transform the given `data` based on the annotations provided in `type_`. - - Note: this function only looks at `Annotated` types that contain `PropertyInfo` metadata. - """ - annotated_type = _get_annotated_type(type_) - if annotated_type is None: - # no `Annotated` definition for this type, no transformation needed - return key - - # ignore the first argument as it is the actual type - annotations = get_args(annotated_type)[1:] - for annotation in annotations: - if isinstance(annotation, PropertyInfo) and annotation.alias is not None: - return annotation.alias - - return key - - -def _no_transform_needed(annotation: type) -> bool: - return annotation == float or annotation == int - - -def _transform_recursive( - data: object, - *, - annotation: type, - inner_type: type | None = None, -) -> object: - """Transform the given data against the expected type. - - Args: - annotation: The direct type annotation given to the particular piece of data. - This may or may not be wrapped in metadata types, e.g. `Required[T]`, `Annotated[T, ...]` etc - - inner_type: If applicable, this is the "inside" type. This is useful in certain cases where the outside type - is a container type such as `List[T]`. In that case `inner_type` should be set to `T` so that each entry in - the list can be transformed using the metadata from the container type. - - Defaults to the same value as the `annotation` argument. - """ - from .._compat import model_dump - - if inner_type is None: - inner_type = annotation - - stripped_type = strip_annotated_type(inner_type) - origin = get_origin(stripped_type) or stripped_type - if is_typeddict(stripped_type) and is_mapping(data): - return _transform_typeddict(data, stripped_type) - - if origin == dict and is_mapping(data): - items_type = get_args(stripped_type)[1] - return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()} - - if ( - # List[T] - (is_list_type(stripped_type) and is_list(data)) - # Iterable[T] - or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) - # Sequence[T] - or (is_sequence_type(stripped_type) and is_sequence(data) and not isinstance(data, str)) - ): - # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually - # intended as an iterable, so we don't transform it. - if isinstance(data, dict): - return cast(object, data) - - inner_type = extract_type_arg(stripped_type, 0) - if _no_transform_needed(inner_type): - # for some types there is no need to transform anything, so we can get a small - # perf boost from skipping that work. - # - # but we still need to convert to a list to ensure the data is json-serializable - if is_list(data): - return data - return list(data) - - return [_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data] - - if is_union_type(stripped_type): - # For union types we run the transformation against all subtypes to ensure that everything is transformed. - # - # TODO: there may be edge cases where the same normalized field name will transform to two different names - # in different subtypes. - for subtype in get_args(stripped_type): - data = _transform_recursive(data, annotation=annotation, inner_type=subtype) - return data - - if isinstance(data, pydantic.BaseModel): - return model_dump(data, exclude_unset=True, mode="json") - - annotated_type = _get_annotated_type(annotation) - if annotated_type is None: - return data - - # ignore the first argument as it is the actual type - annotations = get_args(annotated_type)[1:] - for annotation in annotations: - if isinstance(annotation, PropertyInfo) and annotation.format is not None: - return _format_data(data, annotation.format, annotation.format_template) - - return data - - -def _format_data(data: object, format_: PropertyFormat, format_template: str | None) -> object: - if isinstance(data, (date, datetime)): - if format_ == "iso8601": - if (isinstance(data, datetime)): - return data.isoformat(sep="T", timespec="milliseconds").replace("+00:00", "Z") - else: - return data.isoformat().replace("+00:00", "Z") - - if format_ == "custom" and format_template is not None: - return data.strftime(format_template) - - if format_ == "base64" and is_base64_file_input(data): - binary: str | bytes | None = None - - if isinstance(data, pathlib.Path): - binary = data.read_bytes() - elif isinstance(data, io.IOBase): - binary = data.read() - - if isinstance(binary, str): # type: ignore[unreachable] - binary = binary.encode() - - if not isinstance(binary, bytes): - raise RuntimeError(f"Could not read bytes from {data}; Received {type(binary)}") - - return base64.b64encode(binary).decode("ascii") - - return data - - -def _transform_typeddict( - data: Mapping[str, object], - expected_type: type, -) -> Mapping[str, object]: - result: dict[str, object] = {} - annotations = get_type_hints(expected_type, include_extras=True) - for key, value in data.items(): - if not is_given(value): - # we don't need to include omitted values here as they'll - # be stripped out before the request is sent anyway - continue - - type_ = annotations.get(key) - if type_ is None: - # we do not have a type annotation for this field, leave it as is - result[key] = value - else: - result[_maybe_transform_key(key, type_)] = _transform_recursive(value, annotation=type_) - return result - - -async def async_maybe_transform( - data: object, - expected_type: object, -) -> Any | None: - """Wrapper over `async_transform()` that allows `None` to be passed. - - See `async_transform()` for more details. - """ - if data is None: - return None - return await async_transform(data, expected_type) - - -async def async_transform( - data: _T, - expected_type: object, -) -> _T: - """Transform dictionaries based off of type information from the given type, for example: - - ```py - class Params(TypedDict, total=False): - card_id: Required[Annotated[str, PropertyInfo(alias="cardID")]] - - - transformed = transform({"card_id": ""}, Params) - # {'cardID': ''} - ``` - - Any keys / data that does not have type information given will be included as is. - - It should be noted that the transformations that this function does are not represented in the type system. - """ - transformed = await _async_transform_recursive(data, annotation=cast(type, expected_type)) - return cast(_T, transformed) - - -async def _async_transform_recursive( - data: object, - *, - annotation: type, - inner_type: type | None = None, -) -> object: - """Transform the given data against the expected type. - - Args: - annotation: The direct type annotation given to the particular piece of data. - This may or may not be wrapped in metadata types, e.g. `Required[T]`, `Annotated[T, ...]` etc - - inner_type: If applicable, this is the "inside" type. This is useful in certain cases where the outside type - is a container type such as `List[T]`. In that case `inner_type` should be set to `T` so that each entry in - the list can be transformed using the metadata from the container type. - - Defaults to the same value as the `annotation` argument. - """ - from .._compat import model_dump - - if inner_type is None: - inner_type = annotation - - stripped_type = strip_annotated_type(inner_type) - origin = get_origin(stripped_type) or stripped_type - if is_typeddict(stripped_type) and is_mapping(data): - return await _async_transform_typeddict(data, stripped_type) - - if origin == dict and is_mapping(data): - items_type = get_args(stripped_type)[1] - return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()} - - if ( - # List[T] - (is_list_type(stripped_type) and is_list(data)) - # Iterable[T] - or (is_iterable_type(stripped_type) and is_iterable(data) and not isinstance(data, str)) - # Sequence[T] - or (is_sequence_type(stripped_type) and is_sequence(data) and not isinstance(data, str)) - ): - # dicts are technically iterable, but it is an iterable on the keys of the dict and is not usually - # intended as an iterable, so we don't transform it. - if isinstance(data, dict): - return cast(object, data) - - inner_type = extract_type_arg(stripped_type, 0) - if _no_transform_needed(inner_type): - # for some types there is no need to transform anything, so we can get a small - # perf boost from skipping that work. - # - # but we still need to convert to a list to ensure the data is json-serializable - if is_list(data): - return data - return list(data) - - return [await _async_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data] - - if is_union_type(stripped_type): - # For union types we run the transformation against all subtypes to ensure that everything is transformed. - # - # TODO: there may be edge cases where the same normalized field name will transform to two different names - # in different subtypes. - for subtype in get_args(stripped_type): - data = await _async_transform_recursive(data, annotation=annotation, inner_type=subtype) - return data - - if isinstance(data, pydantic.BaseModel): - return model_dump(data, exclude_unset=True, mode="json") - - annotated_type = _get_annotated_type(annotation) - if annotated_type is None: - return data - - # ignore the first argument as it is the actual type - annotations = get_args(annotated_type)[1:] - for annotation in annotations: - if isinstance(annotation, PropertyInfo) and annotation.format is not None: - return await _async_format_data(data, annotation.format, annotation.format_template) - - return data - - -async def _async_format_data(data: object, format_: PropertyFormat, format_template: str | None) -> object: - if isinstance(data, (date, datetime)): - if format_ == "iso8601": - if (isinstance(data, datetime)): - return data.isoformat(sep="T", timespec="milliseconds").replace("+00:00", "Z") - else: - return data.isoformat().replace("+00:00", "Z") - - if format_ == "custom" and format_template is not None: - return data.strftime(format_template) - - if format_ == "base64" and is_base64_file_input(data): - binary: str | bytes | None = None - - if isinstance(data, pathlib.Path): - binary = await anyio.Path(data).read_bytes() - elif isinstance(data, io.IOBase): - binary = data.read() - - if isinstance(binary, str): # type: ignore[unreachable] - binary = binary.encode() - - if not isinstance(binary, bytes): - raise RuntimeError(f"Could not read bytes from {data}; Received {type(binary)}") - - return base64.b64encode(binary).decode("ascii") - - return data - - -async def _async_transform_typeddict( - data: Mapping[str, object], - expected_type: type, -) -> Mapping[str, object]: - result: dict[str, object] = {} - annotations = get_type_hints(expected_type, include_extras=True) - for key, value in data.items(): - if not is_given(value): - # we don't need to include omitted values here as they'll - # be stripped out before the request is sent anyway - continue - - type_ = annotations.get(key) - if type_ is None: - # we do not have a type annotation for this field, leave it as is - result[key] = value - else: - result[_maybe_transform_key(key, type_)] = await _async_transform_recursive(value, annotation=type_) - return result - - -@lru_cache(maxsize=8096) -def get_type_hints( - obj: Any, - globalns: dict[str, Any] | None = None, - localns: Mapping[str, Any] | None = None, - include_extras: bool = False, -) -> dict[str, Any]: - return _get_type_hints(obj, globalns=globalns, localns=localns, include_extras=include_extras) diff --git a/src/metronome/_utils/_typing.py b/src/metronome/_utils/_typing.py deleted file mode 100644 index 193109f3a..000000000 --- a/src/metronome/_utils/_typing.py +++ /dev/null @@ -1,156 +0,0 @@ -from __future__ import annotations - -import sys -import typing -import typing_extensions -from typing import Any, TypeVar, Iterable, cast -from collections import abc as _c_abc -from typing_extensions import ( - TypeIs, - Required, - Annotated, - get_args, - get_origin, -) - -from ._utils import lru_cache -from .._types import InheritsGeneric -from ._compat import is_union as _is_union - - -def is_annotated_type(typ: type) -> bool: - return get_origin(typ) == Annotated - - -def is_list_type(typ: type) -> bool: - return (get_origin(typ) or typ) == list - - -def is_sequence_type(typ: type) -> bool: - origin = get_origin(typ) or typ - return origin == typing_extensions.Sequence or origin == typing.Sequence or origin == _c_abc.Sequence - - -def is_iterable_type(typ: type) -> bool: - """If the given type is `typing.Iterable[T]`""" - origin = get_origin(typ) or typ - return origin == Iterable or origin == _c_abc.Iterable - - -def is_union_type(typ: type) -> bool: - return _is_union(get_origin(typ)) - - -def is_required_type(typ: type) -> bool: - return get_origin(typ) == Required - - -def is_typevar(typ: type) -> bool: - # type ignore is required because type checkers - # think this expression will always return False - return type(typ) == TypeVar # type: ignore - - -_TYPE_ALIAS_TYPES: tuple[type[typing_extensions.TypeAliasType], ...] = (typing_extensions.TypeAliasType,) -if sys.version_info >= (3, 12): - _TYPE_ALIAS_TYPES = (*_TYPE_ALIAS_TYPES, typing.TypeAliasType) - - -def is_type_alias_type(tp: Any, /) -> TypeIs[typing_extensions.TypeAliasType]: - """Return whether the provided argument is an instance of `TypeAliasType`. - - ```python - type Int = int - is_type_alias_type(Int) - # > True - Str = TypeAliasType("Str", str) - is_type_alias_type(Str) - # > True - ``` - """ - return isinstance(tp, _TYPE_ALIAS_TYPES) - - -# Extracts T from Annotated[T, ...] or from Required[Annotated[T, ...]] -@lru_cache(maxsize=8096) -def strip_annotated_type(typ: type) -> type: - if is_required_type(typ) or is_annotated_type(typ): - return strip_annotated_type(cast(type, get_args(typ)[0])) - - return typ - - -def extract_type_arg(typ: type, index: int) -> type: - args = get_args(typ) - try: - return cast(type, args[index]) - except IndexError as err: - raise RuntimeError(f"Expected type {typ} to have a type argument at index {index} but it did not") from err - - -def extract_type_var_from_base( - typ: type, - *, - generic_bases: tuple[type, ...], - index: int, - failure_message: str | None = None, -) -> type: - """Given a type like `Foo[T]`, returns the generic type variable `T`. - - This also handles the case where a concrete subclass is given, e.g. - ```py - class MyResponse(Foo[bytes]): - ... - - extract_type_var(MyResponse, bases=(Foo,), index=0) -> bytes - ``` - - And where a generic subclass is given: - ```py - _T = TypeVar('_T') - class MyResponse(Foo[_T]): - ... - - extract_type_var(MyResponse[bytes], bases=(Foo,), index=0) -> bytes - ``` - """ - cls = cast(object, get_origin(typ) or typ) - if cls in generic_bases: # pyright: ignore[reportUnnecessaryContains] - # we're given the class directly - return extract_type_arg(typ, index) - - # if a subclass is given - # --- - # this is needed as __orig_bases__ is not present in the typeshed stubs - # because it is intended to be for internal use only, however there does - # not seem to be a way to resolve generic TypeVars for inherited subclasses - # without using it. - if isinstance(cls, InheritsGeneric): - target_base_class: Any | None = None - for base in cls.__orig_bases__: - if base.__origin__ in generic_bases: - target_base_class = base - break - - if target_base_class is None: - raise RuntimeError( - "Could not find the generic base class;\n" - "This should never happen;\n" - f"Does {cls} inherit from one of {generic_bases} ?" - ) - - extracted = extract_type_arg(target_base_class, index) - if is_typevar(extracted): - # If the extracted type argument is itself a type variable - # then that means the subclass itself is generic, so we have - # to resolve the type argument from the class itself, not - # the base class. - # - # Note: if there is more than 1 type argument, the subclass could - # change the ordering of the type arguments, this is not currently - # supported. - return extract_type_arg(typ, index) - - return extracted - - raise RuntimeError(failure_message or f"Could not resolve inner type variable at index {index} for {typ}") diff --git a/src/metronome/_utils/_utils.py b/src/metronome/_utils/_utils.py deleted file mode 100644 index 98aba4614..000000000 --- a/src/metronome/_utils/_utils.py +++ /dev/null @@ -1,421 +0,0 @@ -from __future__ import annotations - -import os -import re -import inspect -import functools -from typing import ( - Any, - Tuple, - Mapping, - TypeVar, - Callable, - Iterable, - Sequence, - cast, - overload, -) -from pathlib import Path -from datetime import date, datetime -from typing_extensions import TypeGuard - -import sniffio - -from .._types import Omit, NotGiven, FileTypes, HeadersLike - -_T = TypeVar("_T") -_TupleT = TypeVar("_TupleT", bound=Tuple[object, ...]) -_MappingT = TypeVar("_MappingT", bound=Mapping[str, object]) -_SequenceT = TypeVar("_SequenceT", bound=Sequence[object]) -CallableT = TypeVar("CallableT", bound=Callable[..., Any]) - - -def flatten(t: Iterable[Iterable[_T]]) -> list[_T]: - return [item for sublist in t for item in sublist] - - -def extract_files( - # TODO: this needs to take Dict but variance issues..... - # create protocol type ? - query: Mapping[str, object], - *, - paths: Sequence[Sequence[str]], -) -> list[tuple[str, FileTypes]]: - """Recursively extract files from the given dictionary based on specified paths. - - A path may look like this ['foo', 'files', '', 'data']. - - Note: this mutates the given dictionary. - """ - files: list[tuple[str, FileTypes]] = [] - for path in paths: - files.extend(_extract_items(query, path, index=0, flattened_key=None)) - return files - - -def _extract_items( - obj: object, - path: Sequence[str], - *, - index: int, - flattened_key: str | None, -) -> list[tuple[str, FileTypes]]: - try: - key = path[index] - except IndexError: - if not is_given(obj): - # no value was provided - we can safely ignore - return [] - - # cyclical import - from .._files import assert_is_file_content - - # We have exhausted the path, return the entry we found. - assert flattened_key is not None - - if is_list(obj): - files: list[tuple[str, FileTypes]] = [] - for entry in obj: - assert_is_file_content(entry, key=flattened_key + "[]" if flattened_key else "") - files.append((flattened_key + "[]", cast(FileTypes, entry))) - return files - - assert_is_file_content(obj, key=flattened_key) - return [(flattened_key, cast(FileTypes, obj))] - - index += 1 - if is_dict(obj): - try: - # We are at the last entry in the path so we must remove the field - if (len(path)) == index: - item = obj.pop(key) - else: - item = obj[key] - except KeyError: - # Key was not present in the dictionary, this is not indicative of an error - # as the given path may not point to a required field. We also do not want - # to enforce required fields as the API may differ from the spec in some cases. - return [] - if flattened_key is None: - flattened_key = key - else: - flattened_key += f"[{key}]" - return _extract_items( - item, - path, - index=index, - flattened_key=flattened_key, - ) - elif is_list(obj): - if key != "": - return [] - - return flatten( - [ - _extract_items( - item, - path, - index=index, - flattened_key=flattened_key + "[]" if flattened_key is not None else "[]", - ) - for item in obj - ] - ) - - # Something unexpected was passed, just ignore it. - return [] - - -def is_given(obj: _T | NotGiven | Omit) -> TypeGuard[_T]: - return not isinstance(obj, NotGiven) and not isinstance(obj, Omit) - - -# Type safe methods for narrowing types with TypeVars. -# The default narrowing for isinstance(obj, dict) is dict[unknown, unknown], -# however this cause Pyright to rightfully report errors. As we know we don't -# care about the contained types we can safely use `object` in its place. -# -# There are two separate functions defined, `is_*` and `is_*_t` for different use cases. -# `is_*` is for when you're dealing with an unknown input -# `is_*_t` is for when you're narrowing a known union type to a specific subset - - -def is_tuple(obj: object) -> TypeGuard[tuple[object, ...]]: - return isinstance(obj, tuple) - - -def is_tuple_t(obj: _TupleT | object) -> TypeGuard[_TupleT]: - return isinstance(obj, tuple) - - -def is_sequence(obj: object) -> TypeGuard[Sequence[object]]: - return isinstance(obj, Sequence) - - -def is_sequence_t(obj: _SequenceT | object) -> TypeGuard[_SequenceT]: - return isinstance(obj, Sequence) - - -def is_mapping(obj: object) -> TypeGuard[Mapping[str, object]]: - return isinstance(obj, Mapping) - - -def is_mapping_t(obj: _MappingT | object) -> TypeGuard[_MappingT]: - return isinstance(obj, Mapping) - - -def is_dict(obj: object) -> TypeGuard[dict[object, object]]: - return isinstance(obj, dict) - - -def is_list(obj: object) -> TypeGuard[list[object]]: - return isinstance(obj, list) - - -def is_iterable(obj: object) -> TypeGuard[Iterable[object]]: - return isinstance(obj, Iterable) - - -def deepcopy_minimal(item: _T) -> _T: - """Minimal reimplementation of copy.deepcopy() that will only copy certain object types: - - - mappings, e.g. `dict` - - list - - This is done for performance reasons. - """ - if is_mapping(item): - return cast(_T, {k: deepcopy_minimal(v) for k, v in item.items()}) - if is_list(item): - return cast(_T, [deepcopy_minimal(entry) for entry in item]) - return item - - -# copied from https://github.com/Rapptz/RoboDanny -def human_join(seq: Sequence[str], *, delim: str = ", ", final: str = "or") -> str: - size = len(seq) - if size == 0: - return "" - - if size == 1: - return seq[0] - - if size == 2: - return f"{seq[0]} {final} {seq[1]}" - - return delim.join(seq[:-1]) + f" {final} {seq[-1]}" - - -def quote(string: str) -> str: - """Add single quotation marks around the given string. Does *not* do any escaping.""" - return f"'{string}'" - - -def required_args(*variants: Sequence[str]) -> Callable[[CallableT], CallableT]: - """Decorator to enforce a given set of arguments or variants of arguments are passed to the decorated function. - - Useful for enforcing runtime validation of overloaded functions. - - Example usage: - ```py - @overload - def foo(*, a: str) -> str: ... - - - @overload - def foo(*, b: bool) -> str: ... - - - # This enforces the same constraints that a static type checker would - # i.e. that either a or b must be passed to the function - @required_args(["a"], ["b"]) - def foo(*, a: str | None = None, b: bool | None = None) -> str: ... - ``` - """ - - def inner(func: CallableT) -> CallableT: - params = inspect.signature(func).parameters - positional = [ - name - for name, param in params.items() - if param.kind - in { - param.POSITIONAL_ONLY, - param.POSITIONAL_OR_KEYWORD, - } - ] - - @functools.wraps(func) - def wrapper(*args: object, **kwargs: object) -> object: - given_params: set[str] = set() - for i, _ in enumerate(args): - try: - given_params.add(positional[i]) - except IndexError: - raise TypeError( - f"{func.__name__}() takes {len(positional)} argument(s) but {len(args)} were given" - ) from None - - for key in kwargs.keys(): - given_params.add(key) - - for variant in variants: - matches = all((param in given_params for param in variant)) - if matches: - break - else: # no break - if len(variants) > 1: - variations = human_join( - ["(" + human_join([quote(arg) for arg in variant], final="and") + ")" for variant in variants] - ) - msg = f"Missing required arguments; Expected either {variations} arguments to be given" - else: - assert len(variants) > 0 - - # TODO: this error message is not deterministic - missing = list(set(variants[0]) - given_params) - if len(missing) > 1: - msg = f"Missing required arguments: {human_join([quote(arg) for arg in missing])}" - else: - msg = f"Missing required argument: {quote(missing[0])}" - raise TypeError(msg) - return func(*args, **kwargs) - - return wrapper # type: ignore - - return inner - - -_K = TypeVar("_K") -_V = TypeVar("_V") - - -@overload -def strip_not_given(obj: None) -> None: ... - - -@overload -def strip_not_given(obj: Mapping[_K, _V | NotGiven]) -> dict[_K, _V]: ... - - -@overload -def strip_not_given(obj: object) -> object: ... - - -def strip_not_given(obj: object | None) -> object: - """Remove all top-level keys where their values are instances of `NotGiven`""" - if obj is None: - return None - - if not is_mapping(obj): - return obj - - return {key: value for key, value in obj.items() if not isinstance(value, NotGiven)} - - -def coerce_integer(val: str) -> int: - return int(val, base=10) - - -def coerce_float(val: str) -> float: - return float(val) - - -def coerce_boolean(val: str) -> bool: - return val == "true" or val == "1" or val == "on" - - -def maybe_coerce_integer(val: str | None) -> int | None: - if val is None: - return None - return coerce_integer(val) - - -def maybe_coerce_float(val: str | None) -> float | None: - if val is None: - return None - return coerce_float(val) - - -def maybe_coerce_boolean(val: str | None) -> bool | None: - if val is None: - return None - return coerce_boolean(val) - - -def removeprefix(string: str, prefix: str) -> str: - """Remove a prefix from a string. - - Backport of `str.removeprefix` for Python < 3.9 - """ - if string.startswith(prefix): - return string[len(prefix) :] - return string - - -def removesuffix(string: str, suffix: str) -> str: - """Remove a suffix from a string. - - Backport of `str.removesuffix` for Python < 3.9 - """ - if string.endswith(suffix): - return string[: -len(suffix)] - return string - - -def file_from_path(path: str) -> FileTypes: - contents = Path(path).read_bytes() - file_name = os.path.basename(path) - return (file_name, contents) - - -def get_required_header(headers: HeadersLike, header: str) -> str: - lower_header = header.lower() - if is_mapping_t(headers): - # mypy doesn't understand the type narrowing here - for k, v in headers.items(): # type: ignore - if k.lower() == lower_header and isinstance(v, str): - return v - - # to deal with the case where the header looks like Stainless-Event-Id - intercaps_header = re.sub(r"([^\w])(\w)", lambda pat: pat.group(1) + pat.group(2).upper(), header.capitalize()) - - for normalized_header in [header, lower_header, header.upper(), intercaps_header]: - value = headers.get(normalized_header) - if value: - return value - - raise ValueError(f"Could not find {header} header") - - -def get_async_library() -> str: - try: - return sniffio.current_async_library() - except Exception: - return "false" - - -def lru_cache(*, maxsize: int | None = 128) -> Callable[[CallableT], CallableT]: - """A version of functools.lru_cache that retains the type signature - for the wrapped function arguments. - """ - wrapper = functools.lru_cache( # noqa: TID251 - maxsize=maxsize, - ) - return cast(Any, wrapper) # type: ignore[no-any-return] - - -def json_safe(data: object) -> object: - """Translates a mapping / sequence recursively in the same fashion - as `pydantic` v2's `model_dump(mode="json")`. - """ - if is_mapping(data): - return {json_safe(key): json_safe(value) for key, value in data.items()} - - if is_iterable(data) and not isinstance(data, (str, bytes, bytearray)): - return [json_safe(item) for item in data] - - if isinstance(data, (datetime, date)): - return data.isoformat().replace("+00:00", "Z") - - return data diff --git a/src/metronome/_version.py b/src/metronome/_version.py deleted file mode 100644 index ee4e18a13..000000000 --- a/src/metronome/_version.py +++ /dev/null @@ -1,4 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -__title__ = "metronome" -__version__ = "4.4.0" # x-release-please-version diff --git a/src/metronome/lib/.keep b/src/metronome/lib/.keep deleted file mode 100644 index 5e2c99fdb..000000000 --- a/src/metronome/lib/.keep +++ /dev/null @@ -1,4 +0,0 @@ -File generated from our OpenAPI spec by Stainless. - -This directory can be used to store custom files to expand the SDK. -It is ignored by Stainless code generation and its content (other than this keep file) won't be touched. \ No newline at end of file diff --git a/src/metronome/pagination.py b/src/metronome/pagination.py deleted file mode 100644 index b2c5744e3..000000000 --- a/src/metronome/pagination.py +++ /dev/null @@ -1,173 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Generic, TypeVar, Optional -from typing_extensions import override - -from ._base_client import BasePage, PageInfo, BaseSyncPage, BaseAsyncPage - -__all__ = [ - "SyncCursorPage", - "AsyncCursorPage", - "SyncBodyCursorPage", - "AsyncBodyCursorPage", - "SyncCursorPageWithoutLimit", - "AsyncCursorPageWithoutLimit", -] - -_T = TypeVar("_T") - - -class SyncCursorPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): - next_page: Optional[str] = None - """Cursor to fetch the next page""" - data: List[_T] - """Items of the page""" - - @override - def _get_page_items(self) -> List[_T]: - data = self.data - if not data: - return [] - return data - - @override - def has_next_page(self) -> bool: - return self.next_page_info() is not None - - @override - def next_page_info(self) -> Optional[PageInfo]: - next_page = self.next_page - if not next_page: - return None - - return PageInfo(params={"next_page": next_page}) - - -class AsyncCursorPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): - next_page: Optional[str] = None - """Cursor to fetch the next page""" - data: List[_T] - """Items of the page""" - - @override - def _get_page_items(self) -> List[_T]: - data = self.data - if not data: - return [] - return data - - @override - def has_next_page(self) -> bool: - return self.next_page_info() is not None - - @override - def next_page_info(self) -> Optional[PageInfo]: - next_page = self.next_page - if not next_page: - return None - - return PageInfo(params={"next_page": next_page}) - - -class SyncBodyCursorPage(BaseSyncPage[_T], BasePage[_T], Generic[_T]): - next_page: Optional[str] = None - """Cursor to fetch the next page""" - data: List[_T] - """Items of the page""" - - @override - def _get_page_items(self) -> List[_T]: - data = self.data - if not data: - return [] - return data - - @override - def has_next_page(self) -> bool: - return self.next_page_info() is not None - - @override - def next_page_info(self) -> Optional[PageInfo]: - next_page = self.next_page - if not next_page: - return None - - return PageInfo(json={"next_page": next_page}) - - -class AsyncBodyCursorPage(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): - next_page: Optional[str] = None - """Cursor to fetch the next page""" - data: List[_T] - """Items of the page""" - - @override - def _get_page_items(self) -> List[_T]: - data = self.data - if not data: - return [] - return data - - @override - def has_next_page(self) -> bool: - return self.next_page_info() is not None - - @override - def next_page_info(self) -> Optional[PageInfo]: - next_page = self.next_page - if not next_page: - return None - - return PageInfo(json={"next_page": next_page}) - - -class SyncCursorPageWithoutLimit(BaseSyncPage[_T], BasePage[_T], Generic[_T]): - next_page: Optional[str] = None - """Cursor to fetch the next page""" - data: List[_T] - """Items of the page""" - - @override - def _get_page_items(self) -> List[_T]: - data = self.data - if not data: - return [] - return data - - @override - def has_next_page(self) -> bool: - return self.next_page_info() is not None - - @override - def next_page_info(self) -> Optional[PageInfo]: - next_page = self.next_page - if not next_page: - return None - - return PageInfo(params={"next_page": next_page}) - - -class AsyncCursorPageWithoutLimit(BaseAsyncPage[_T], BasePage[_T], Generic[_T]): - next_page: Optional[str] = None - """Cursor to fetch the next page""" - data: List[_T] - """Items of the page""" - - @override - def _get_page_items(self) -> List[_T]: - data = self.data - if not data: - return [] - return data - - @override - def has_next_page(self) -> bool: - return self.next_page_info() is not None - - @override - def next_page_info(self) -> Optional[PageInfo]: - next_page = self.next_page - if not next_page: - return None - - return PageInfo(params={"next_page": next_page}) diff --git a/src/metronome/py.typed b/src/metronome/py.typed deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/metronome/resources/__init__.py b/src/metronome/resources/__init__.py deleted file mode 100644 index 334f2a64a..000000000 --- a/src/metronome/resources/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .v1 import ( - V1Resource, - AsyncV1Resource, - V1ResourceWithRawResponse, - AsyncV1ResourceWithRawResponse, - V1ResourceWithStreamingResponse, - AsyncV1ResourceWithStreamingResponse, -) -from .v2 import ( - V2Resource, - AsyncV2Resource, - V2ResourceWithRawResponse, - AsyncV2ResourceWithRawResponse, - V2ResourceWithStreamingResponse, - AsyncV2ResourceWithStreamingResponse, -) - -__all__ = [ - "V2Resource", - "AsyncV2Resource", - "V2ResourceWithRawResponse", - "AsyncV2ResourceWithRawResponse", - "V2ResourceWithStreamingResponse", - "AsyncV2ResourceWithStreamingResponse", - "V1Resource", - "AsyncV1Resource", - "V1ResourceWithRawResponse", - "AsyncV1ResourceWithRawResponse", - "V1ResourceWithStreamingResponse", - "AsyncV1ResourceWithStreamingResponse", -] diff --git a/src/metronome/resources/v1/__init__.py b/src/metronome/resources/v1/__init__.py deleted file mode 100644 index 1319a76f6..000000000 --- a/src/metronome/resources/v1/__init__.py +++ /dev/null @@ -1,243 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .v1 import ( - V1Resource, - AsyncV1Resource, - V1ResourceWithRawResponse, - AsyncV1ResourceWithRawResponse, - V1ResourceWithStreamingResponse, - AsyncV1ResourceWithStreamingResponse, -) -from .plans import ( - PlansResource, - AsyncPlansResource, - PlansResourceWithRawResponse, - AsyncPlansResourceWithRawResponse, - PlansResourceWithStreamingResponse, - AsyncPlansResourceWithStreamingResponse, -) -from .usage import ( - UsageResource, - AsyncUsageResource, - UsageResourceWithRawResponse, - AsyncUsageResourceWithRawResponse, - UsageResourceWithStreamingResponse, - AsyncUsageResourceWithStreamingResponse, -) -from .alerts import ( - AlertsResource, - AsyncAlertsResource, - AlertsResourceWithRawResponse, - AsyncAlertsResourceWithRawResponse, - AlertsResourceWithStreamingResponse, - AsyncAlertsResourceWithStreamingResponse, -) -from .invoices import ( - InvoicesResource, - AsyncInvoicesResource, - InvoicesResourceWithRawResponse, - AsyncInvoicesResourceWithRawResponse, - InvoicesResourceWithStreamingResponse, - AsyncInvoicesResourceWithStreamingResponse, -) -from .packages import ( - PackagesResource, - AsyncPackagesResource, - PackagesResourceWithRawResponse, - AsyncPackagesResourceWithRawResponse, - PackagesResourceWithStreamingResponse, - AsyncPackagesResourceWithStreamingResponse, -) -from .payments import ( - PaymentsResource, - AsyncPaymentsResource, - PaymentsResourceWithRawResponse, - AsyncPaymentsResourceWithRawResponse, - PaymentsResourceWithStreamingResponse, - AsyncPaymentsResourceWithStreamingResponse, -) -from .services import ( - ServicesResource, - AsyncServicesResource, - ServicesResourceWithRawResponse, - AsyncServicesResourceWithRawResponse, - ServicesResourceWithStreamingResponse, - AsyncServicesResourceWithStreamingResponse, -) -from .settings import ( - SettingsResource, - AsyncSettingsResource, - SettingsResourceWithRawResponse, - AsyncSettingsResourceWithRawResponse, - SettingsResourceWithStreamingResponse, - AsyncSettingsResourceWithStreamingResponse, -) -from .contracts import ( - ContractsResource, - AsyncContractsResource, - ContractsResourceWithRawResponse, - AsyncContractsResourceWithRawResponse, - ContractsResourceWithStreamingResponse, - AsyncContractsResourceWithStreamingResponse, -) -from .customers import ( - CustomersResource, - AsyncCustomersResource, - CustomersResourceWithRawResponse, - AsyncCustomersResourceWithRawResponse, - CustomersResourceWithStreamingResponse, - AsyncCustomersResourceWithStreamingResponse, -) -from .audit_logs import ( - AuditLogsResource, - AsyncAuditLogsResource, - AuditLogsResourceWithRawResponse, - AsyncAuditLogsResourceWithRawResponse, - AuditLogsResourceWithStreamingResponse, - AsyncAuditLogsResourceWithStreamingResponse, -) -from .dashboards import ( - DashboardsResource, - AsyncDashboardsResource, - DashboardsResourceWithRawResponse, - AsyncDashboardsResourceWithRawResponse, - DashboardsResourceWithStreamingResponse, - AsyncDashboardsResourceWithStreamingResponse, -) -from .credit_grants import ( - CreditGrantsResource, - AsyncCreditGrantsResource, - CreditGrantsResourceWithRawResponse, - AsyncCreditGrantsResourceWithRawResponse, - CreditGrantsResourceWithStreamingResponse, - AsyncCreditGrantsResourceWithStreamingResponse, -) -from .custom_fields import ( - CustomFieldsResource, - AsyncCustomFieldsResource, - CustomFieldsResourceWithRawResponse, - AsyncCustomFieldsResourceWithRawResponse, - CustomFieldsResourceWithStreamingResponse, - AsyncCustomFieldsResourceWithStreamingResponse, -) -from .pricing_units import ( - PricingUnitsResource, - AsyncPricingUnitsResource, - PricingUnitsResourceWithRawResponse, - AsyncPricingUnitsResourceWithRawResponse, - PricingUnitsResourceWithStreamingResponse, - AsyncPricingUnitsResourceWithStreamingResponse, -) -from .billable_metrics import ( - BillableMetricsResource, - AsyncBillableMetricsResource, - BillableMetricsResourceWithRawResponse, - AsyncBillableMetricsResourceWithRawResponse, - BillableMetricsResourceWithStreamingResponse, - AsyncBillableMetricsResourceWithStreamingResponse, -) - -__all__ = [ - "AlertsResource", - "AsyncAlertsResource", - "AlertsResourceWithRawResponse", - "AsyncAlertsResourceWithRawResponse", - "AlertsResourceWithStreamingResponse", - "AsyncAlertsResourceWithStreamingResponse", - "PlansResource", - "AsyncPlansResource", - "PlansResourceWithRawResponse", - "AsyncPlansResourceWithRawResponse", - "PlansResourceWithStreamingResponse", - "AsyncPlansResourceWithStreamingResponse", - "CreditGrantsResource", - "AsyncCreditGrantsResource", - "CreditGrantsResourceWithRawResponse", - "AsyncCreditGrantsResourceWithRawResponse", - "CreditGrantsResourceWithStreamingResponse", - "AsyncCreditGrantsResourceWithStreamingResponse", - "PricingUnitsResource", - "AsyncPricingUnitsResource", - "PricingUnitsResourceWithRawResponse", - "AsyncPricingUnitsResourceWithRawResponse", - "PricingUnitsResourceWithStreamingResponse", - "AsyncPricingUnitsResourceWithStreamingResponse", - "CustomersResource", - "AsyncCustomersResource", - "CustomersResourceWithRawResponse", - "AsyncCustomersResourceWithRawResponse", - "CustomersResourceWithStreamingResponse", - "AsyncCustomersResourceWithStreamingResponse", - "DashboardsResource", - "AsyncDashboardsResource", - "DashboardsResourceWithRawResponse", - "AsyncDashboardsResourceWithRawResponse", - "DashboardsResourceWithStreamingResponse", - "AsyncDashboardsResourceWithStreamingResponse", - "UsageResource", - "AsyncUsageResource", - "UsageResourceWithRawResponse", - "AsyncUsageResourceWithRawResponse", - "UsageResourceWithStreamingResponse", - "AsyncUsageResourceWithStreamingResponse", - "AuditLogsResource", - "AsyncAuditLogsResource", - "AuditLogsResourceWithRawResponse", - "AsyncAuditLogsResourceWithRawResponse", - "AuditLogsResourceWithStreamingResponse", - "AsyncAuditLogsResourceWithStreamingResponse", - "CustomFieldsResource", - "AsyncCustomFieldsResource", - "CustomFieldsResourceWithRawResponse", - "AsyncCustomFieldsResourceWithRawResponse", - "CustomFieldsResourceWithStreamingResponse", - "AsyncCustomFieldsResourceWithStreamingResponse", - "BillableMetricsResource", - "AsyncBillableMetricsResource", - "BillableMetricsResourceWithRawResponse", - "AsyncBillableMetricsResourceWithRawResponse", - "BillableMetricsResourceWithStreamingResponse", - "AsyncBillableMetricsResourceWithStreamingResponse", - "ServicesResource", - "AsyncServicesResource", - "ServicesResourceWithRawResponse", - "AsyncServicesResourceWithRawResponse", - "ServicesResourceWithStreamingResponse", - "AsyncServicesResourceWithStreamingResponse", - "InvoicesResource", - "AsyncInvoicesResource", - "InvoicesResourceWithRawResponse", - "AsyncInvoicesResourceWithRawResponse", - "InvoicesResourceWithStreamingResponse", - "AsyncInvoicesResourceWithStreamingResponse", - "ContractsResource", - "AsyncContractsResource", - "ContractsResourceWithRawResponse", - "AsyncContractsResourceWithRawResponse", - "ContractsResourceWithStreamingResponse", - "AsyncContractsResourceWithStreamingResponse", - "PackagesResource", - "AsyncPackagesResource", - "PackagesResourceWithRawResponse", - "AsyncPackagesResourceWithRawResponse", - "PackagesResourceWithStreamingResponse", - "AsyncPackagesResourceWithStreamingResponse", - "PaymentsResource", - "AsyncPaymentsResource", - "PaymentsResourceWithRawResponse", - "AsyncPaymentsResourceWithRawResponse", - "PaymentsResourceWithStreamingResponse", - "AsyncPaymentsResourceWithStreamingResponse", - "SettingsResource", - "AsyncSettingsResource", - "SettingsResourceWithRawResponse", - "AsyncSettingsResourceWithRawResponse", - "SettingsResourceWithStreamingResponse", - "AsyncSettingsResourceWithStreamingResponse", - "V1Resource", - "AsyncV1Resource", - "V1ResourceWithRawResponse", - "AsyncV1ResourceWithRawResponse", - "V1ResourceWithStreamingResponse", - "AsyncV1ResourceWithStreamingResponse", -] diff --git a/src/metronome/resources/v1/alerts.py b/src/metronome/resources/v1/alerts.py deleted file mode 100644 index 29d5596e1..000000000 --- a/src/metronome/resources/v1/alerts.py +++ /dev/null @@ -1,603 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable -from typing_extensions import Literal - -import httpx - -from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ...types.v1 import alert_create_params, alert_archive_params -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ..._base_client import make_request_options -from ...types.v1.alert_create_response import AlertCreateResponse -from ...types.v1.alert_archive_response import AlertArchiveResponse - -__all__ = ["AlertsResource", "AsyncAlertsResource"] - - -class AlertsResource(SyncAPIResource): - """ - [Alerts](https://docs.metronome.com/connecting-metronome/alerts/) monitor customer spending, balances, and other billing factors. Use these endpoints to create, retrieve, and archive customer alerts. To view sample alert payloads by alert type, navigate [here.](https://docs.metronome.com/manage-product-access/create-manage-alerts/#webhook-notifications) - """ - - @cached_property - def with_raw_response(self) -> AlertsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AlertsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AlertsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AlertsResourceWithStreamingResponse(self) - - def create( - self, - *, - alert_type: Literal[ - "low_credit_balance_reached", - "spend_threshold_reached", - "monthly_invoice_total_spend_threshold_reached", - "low_remaining_days_in_plan_reached", - "low_remaining_credit_percentage_reached", - "usage_threshold_reached", - "low_remaining_days_for_commit_segment_reached", - "low_remaining_commit_balance_reached", - "low_remaining_commit_percentage_reached", - "low_remaining_days_for_contract_credit_segment_reached", - "low_remaining_contract_credit_balance_reached", - "low_remaining_contract_credit_percentage_reached", - "low_remaining_contract_credit_and_commit_balance_reached", - "invoice_total_reached", - "low_remaining_seat_balance_reached", - ], - name: str, - threshold: float, - billable_metric_id: str | Omit = omit, - credit_grant_type_filters: SequenceNotStr[str] | Omit = omit, - credit_type_id: str | Omit = omit, - custom_field_filters: Iterable[alert_create_params.CustomFieldFilter] | Omit = omit, - customer_id: str | Omit = omit, - evaluate_on_create: bool | Omit = omit, - group_values: Iterable[alert_create_params.GroupValue] | Omit = omit, - invoice_types_filter: SequenceNotStr[str] | Omit = omit, - plan_id: str | Omit = omit, - seat_filter: alert_create_params.SeatFilter | Omit = omit, - uniqueness_key: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AlertCreateResponse: - """ - Create a new threshold notification to monitor customer spending, balances, and - billing metrics in real-time. Metronome's notification system provides - industry-leading speed with immediate evaluation capabilities, enabling you to - proactively manage customer accounts and prevent revenue leakage. - - This endpoint creates configurable threshold notifications that continuously - monitor various billing thresholds including spend limits, credit balances, - commitment utilization, and invoice totals. Threshold notifications can be - configured globally for all customers or targeted to specific customer accounts. - - ### Use this endpoint to: - - - Proactively monitor customer spending patterns to prevent unexpected overages - or credit exhaustion - - Automate notifications when customers approach commitment limits or credit - thresholds - - Enable real-time intervention for accounts at risk of churn or payment issues - - Scale billing operations by automating threshold-based workflows and - notifications - - ### Key response fields: - - A successful response returns a CustomerAlert object containing: - - - The threshold notification configuration with its unique ID and current status - - The customer's evaluation status (ok, in_alarm, or evaluating) - - Threshold notification metadata including type, threshold values, and update - timestamps - - ### Usage guidelines: - - - Immediate evaluation: Set `evaluate_on_create` : `true` (default) for instant - evaluation against existing customers - - Uniqueness constraints: Each threshold notification must have a unique - `uniqueness_key` within your organization. Use `release_uniqueness_key` : - `true` when archiving to reuse keys - - Notification type requirements: Different threshold notification types require - specific fields (e.g., `billable_metric_id` for usage notifications, - `credit_type_id` for credit-based threshold notifications) - - Webhook delivery: Threshold notifications trigger webhook notifications for - real-time integration with your systems. Configure webhook endpoints before - creating threshold notifications - - Performance at scale: Metronome's event-driven architecture processes - threshold notification evaluations in real-time as usage events stream in, - unlike competitors who rely on periodic polling or batch evaluation cycles - - Args: - alert_type: Type of the threshold notification - - name: Name of the threshold notification - - threshold: Threshold value of the notification policy. Depending upon the notification - type, this number may represent a financial amount, the days remaining, or a - percentage reached. - - billable_metric_id: For threshold notifications of type `usage_threshold_reached`, specifies which - billable metric to track the usage for. - - credit_grant_type_filters: An array of strings, representing a way to filter the credit grant this - threshold notification applies to, by looking at the credit_grant_type field on - the credit grant. This field is only defined for CreditPercentage and - CreditBalance notifications - - credit_type_id: ID of the credit's currency, defaults to USD. If the specific notification type - requires a pricing unit/currency, find the ID in the - [Metronome app](https://app.metronome.com/offering/pricing-units). - - custom_field_filters: A list of custom field filters for threshold notification types that support - advanced filtering. Only present for contract invoices. - - customer_id: If provided, will create this threshold notification for this specific customer. - To create a notification for all customers, do not specify a `customer_id`. - - evaluate_on_create: If true, the threshold notification will evaluate immediately on customers that - already meet the notification threshold. If false, it will only evaluate on - future customers that trigger the threshold. Defaults to true. - - group_values: Only present for `spend_threshold_reached` notifications. Scope notification to - a specific group key on individual line items. - - invoice_types_filter: Only supported for invoice_total_reached threshold notifications. A list of - invoice types to evaluate. - - plan_id: If provided, will create this threshold notification for this specific plan. To - create a notification for all customers, do not specify a `plan_id`. - - seat_filter: Required for `low_remaining_seat_balance_reached` notifications. The alert is - scoped to this seat group key-value pair. - - uniqueness_key: Prevents the creation of duplicates. If a request to create a record is made - with a previously used uniqueness key, a new record will not be created and the - request will fail with a 409 error. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/alerts/create", - body=maybe_transform( - { - "alert_type": alert_type, - "name": name, - "threshold": threshold, - "billable_metric_id": billable_metric_id, - "credit_grant_type_filters": credit_grant_type_filters, - "credit_type_id": credit_type_id, - "custom_field_filters": custom_field_filters, - "customer_id": customer_id, - "evaluate_on_create": evaluate_on_create, - "group_values": group_values, - "invoice_types_filter": invoice_types_filter, - "plan_id": plan_id, - "seat_filter": seat_filter, - "uniqueness_key": uniqueness_key, - }, - alert_create_params.AlertCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=AlertCreateResponse, - ) - - def archive( - self, - *, - id: str, - release_uniqueness_key: bool | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AlertArchiveResponse: - """ - Permanently disable a threshold notification and remove it from active - monitoring across all customers. Archived threshold notifications stop - evaluating immediately and can optionally release their uniqueness key for reuse - in future threshold notification configurations. - - ### Use this endpoint to: - - - Decommission threshold notifications that are no longer needed - - Clean up test or deprecated threshold notification configurations - - Free up uniqueness keys for reuse with new threshold notifications - - Stop threshold notification evaluations without losing historical - configuration data - - Disable outdated monitoring rules during pricing model transitions - - ### Key response fields: - - - data: Object containing the archived threshold notification's ID - - ### Usage guidelines: - - - Irreversible for evaluation: Archived threshold notifications cannot be - re-enabled; create a new threshold notification to resume monitoring - - Uniqueness key handling: Set `release_uniqueness_key` : `true` to reuse the - key in future threshold notifications - - Immediate effect: Threshold notification evaluation stops instantly across all - customers - - Historical preservation: Archive operation maintains threshold notification - history and configuration for compliance and auditing - - Args: - id: The Metronome ID of the threshold notification - - release_uniqueness_key: If true, resets the uniqueness key on this threshold notification so it can be - re-used - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/alerts/archive", - body=maybe_transform( - { - "id": id, - "release_uniqueness_key": release_uniqueness_key, - }, - alert_archive_params.AlertArchiveParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=AlertArchiveResponse, - ) - - -class AsyncAlertsResource(AsyncAPIResource): - """ - [Alerts](https://docs.metronome.com/connecting-metronome/alerts/) monitor customer spending, balances, and other billing factors. Use these endpoints to create, retrieve, and archive customer alerts. To view sample alert payloads by alert type, navigate [here.](https://docs.metronome.com/manage-product-access/create-manage-alerts/#webhook-notifications) - """ - - @cached_property - def with_raw_response(self) -> AsyncAlertsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncAlertsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncAlertsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncAlertsResourceWithStreamingResponse(self) - - async def create( - self, - *, - alert_type: Literal[ - "low_credit_balance_reached", - "spend_threshold_reached", - "monthly_invoice_total_spend_threshold_reached", - "low_remaining_days_in_plan_reached", - "low_remaining_credit_percentage_reached", - "usage_threshold_reached", - "low_remaining_days_for_commit_segment_reached", - "low_remaining_commit_balance_reached", - "low_remaining_commit_percentage_reached", - "low_remaining_days_for_contract_credit_segment_reached", - "low_remaining_contract_credit_balance_reached", - "low_remaining_contract_credit_percentage_reached", - "low_remaining_contract_credit_and_commit_balance_reached", - "invoice_total_reached", - "low_remaining_seat_balance_reached", - ], - name: str, - threshold: float, - billable_metric_id: str | Omit = omit, - credit_grant_type_filters: SequenceNotStr[str] | Omit = omit, - credit_type_id: str | Omit = omit, - custom_field_filters: Iterable[alert_create_params.CustomFieldFilter] | Omit = omit, - customer_id: str | Omit = omit, - evaluate_on_create: bool | Omit = omit, - group_values: Iterable[alert_create_params.GroupValue] | Omit = omit, - invoice_types_filter: SequenceNotStr[str] | Omit = omit, - plan_id: str | Omit = omit, - seat_filter: alert_create_params.SeatFilter | Omit = omit, - uniqueness_key: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AlertCreateResponse: - """ - Create a new threshold notification to monitor customer spending, balances, and - billing metrics in real-time. Metronome's notification system provides - industry-leading speed with immediate evaluation capabilities, enabling you to - proactively manage customer accounts and prevent revenue leakage. - - This endpoint creates configurable threshold notifications that continuously - monitor various billing thresholds including spend limits, credit balances, - commitment utilization, and invoice totals. Threshold notifications can be - configured globally for all customers or targeted to specific customer accounts. - - ### Use this endpoint to: - - - Proactively monitor customer spending patterns to prevent unexpected overages - or credit exhaustion - - Automate notifications when customers approach commitment limits or credit - thresholds - - Enable real-time intervention for accounts at risk of churn or payment issues - - Scale billing operations by automating threshold-based workflows and - notifications - - ### Key response fields: - - A successful response returns a CustomerAlert object containing: - - - The threshold notification configuration with its unique ID and current status - - The customer's evaluation status (ok, in_alarm, or evaluating) - - Threshold notification metadata including type, threshold values, and update - timestamps - - ### Usage guidelines: - - - Immediate evaluation: Set `evaluate_on_create` : `true` (default) for instant - evaluation against existing customers - - Uniqueness constraints: Each threshold notification must have a unique - `uniqueness_key` within your organization. Use `release_uniqueness_key` : - `true` when archiving to reuse keys - - Notification type requirements: Different threshold notification types require - specific fields (e.g., `billable_metric_id` for usage notifications, - `credit_type_id` for credit-based threshold notifications) - - Webhook delivery: Threshold notifications trigger webhook notifications for - real-time integration with your systems. Configure webhook endpoints before - creating threshold notifications - - Performance at scale: Metronome's event-driven architecture processes - threshold notification evaluations in real-time as usage events stream in, - unlike competitors who rely on periodic polling or batch evaluation cycles - - Args: - alert_type: Type of the threshold notification - - name: Name of the threshold notification - - threshold: Threshold value of the notification policy. Depending upon the notification - type, this number may represent a financial amount, the days remaining, or a - percentage reached. - - billable_metric_id: For threshold notifications of type `usage_threshold_reached`, specifies which - billable metric to track the usage for. - - credit_grant_type_filters: An array of strings, representing a way to filter the credit grant this - threshold notification applies to, by looking at the credit_grant_type field on - the credit grant. This field is only defined for CreditPercentage and - CreditBalance notifications - - credit_type_id: ID of the credit's currency, defaults to USD. If the specific notification type - requires a pricing unit/currency, find the ID in the - [Metronome app](https://app.metronome.com/offering/pricing-units). - - custom_field_filters: A list of custom field filters for threshold notification types that support - advanced filtering. Only present for contract invoices. - - customer_id: If provided, will create this threshold notification for this specific customer. - To create a notification for all customers, do not specify a `customer_id`. - - evaluate_on_create: If true, the threshold notification will evaluate immediately on customers that - already meet the notification threshold. If false, it will only evaluate on - future customers that trigger the threshold. Defaults to true. - - group_values: Only present for `spend_threshold_reached` notifications. Scope notification to - a specific group key on individual line items. - - invoice_types_filter: Only supported for invoice_total_reached threshold notifications. A list of - invoice types to evaluate. - - plan_id: If provided, will create this threshold notification for this specific plan. To - create a notification for all customers, do not specify a `plan_id`. - - seat_filter: Required for `low_remaining_seat_balance_reached` notifications. The alert is - scoped to this seat group key-value pair. - - uniqueness_key: Prevents the creation of duplicates. If a request to create a record is made - with a previously used uniqueness key, a new record will not be created and the - request will fail with a 409 error. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/alerts/create", - body=await async_maybe_transform( - { - "alert_type": alert_type, - "name": name, - "threshold": threshold, - "billable_metric_id": billable_metric_id, - "credit_grant_type_filters": credit_grant_type_filters, - "credit_type_id": credit_type_id, - "custom_field_filters": custom_field_filters, - "customer_id": customer_id, - "evaluate_on_create": evaluate_on_create, - "group_values": group_values, - "invoice_types_filter": invoice_types_filter, - "plan_id": plan_id, - "seat_filter": seat_filter, - "uniqueness_key": uniqueness_key, - }, - alert_create_params.AlertCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=AlertCreateResponse, - ) - - async def archive( - self, - *, - id: str, - release_uniqueness_key: bool | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AlertArchiveResponse: - """ - Permanently disable a threshold notification and remove it from active - monitoring across all customers. Archived threshold notifications stop - evaluating immediately and can optionally release their uniqueness key for reuse - in future threshold notification configurations. - - ### Use this endpoint to: - - - Decommission threshold notifications that are no longer needed - - Clean up test or deprecated threshold notification configurations - - Free up uniqueness keys for reuse with new threshold notifications - - Stop threshold notification evaluations without losing historical - configuration data - - Disable outdated monitoring rules during pricing model transitions - - ### Key response fields: - - - data: Object containing the archived threshold notification's ID - - ### Usage guidelines: - - - Irreversible for evaluation: Archived threshold notifications cannot be - re-enabled; create a new threshold notification to resume monitoring - - Uniqueness key handling: Set `release_uniqueness_key` : `true` to reuse the - key in future threshold notifications - - Immediate effect: Threshold notification evaluation stops instantly across all - customers - - Historical preservation: Archive operation maintains threshold notification - history and configuration for compliance and auditing - - Args: - id: The Metronome ID of the threshold notification - - release_uniqueness_key: If true, resets the uniqueness key on this threshold notification so it can be - re-used - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/alerts/archive", - body=await async_maybe_transform( - { - "id": id, - "release_uniqueness_key": release_uniqueness_key, - }, - alert_archive_params.AlertArchiveParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=AlertArchiveResponse, - ) - - -class AlertsResourceWithRawResponse: - def __init__(self, alerts: AlertsResource) -> None: - self._alerts = alerts - - self.create = to_raw_response_wrapper( - alerts.create, - ) - self.archive = to_raw_response_wrapper( - alerts.archive, - ) - - -class AsyncAlertsResourceWithRawResponse: - def __init__(self, alerts: AsyncAlertsResource) -> None: - self._alerts = alerts - - self.create = async_to_raw_response_wrapper( - alerts.create, - ) - self.archive = async_to_raw_response_wrapper( - alerts.archive, - ) - - -class AlertsResourceWithStreamingResponse: - def __init__(self, alerts: AlertsResource) -> None: - self._alerts = alerts - - self.create = to_streamed_response_wrapper( - alerts.create, - ) - self.archive = to_streamed_response_wrapper( - alerts.archive, - ) - - -class AsyncAlertsResourceWithStreamingResponse: - def __init__(self, alerts: AsyncAlertsResource) -> None: - self._alerts = alerts - - self.create = async_to_streamed_response_wrapper( - alerts.create, - ) - self.archive = async_to_streamed_response_wrapper( - alerts.archive, - ) diff --git a/src/metronome/resources/v1/audit_logs.py b/src/metronome/resources/v1/audit_logs.py deleted file mode 100644 index cdffdedbb..000000000 --- a/src/metronome/resources/v1/audit_logs.py +++ /dev/null @@ -1,328 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Literal - -import httpx - -from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform -from ..._compat import cached_property -from ...types.v1 import audit_log_list_params -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ...pagination import SyncCursorPage, AsyncCursorPage -from ..._base_client import AsyncPaginator, make_request_options -from ...types.v1.audit_log_list_response import AuditLogListResponse - -__all__ = ["AuditLogsResource", "AsyncAuditLogsResource"] - - -class AuditLogsResource(SyncAPIResource): - """ - [Security](https://docs.metronome.com/developer-resources/security/) endpoints allow you to retrieve security-related data. - """ - - @cached_property - def with_raw_response(self) -> AuditLogsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AuditLogsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AuditLogsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AuditLogsResourceWithStreamingResponse(self) - - def list( - self, - *, - ending_before: Union[str, datetime] | Omit = omit, - limit: int | Omit = omit, - next_page: str | Omit = omit, - resource_id: str | Omit = omit, - resource_type: str | Omit = omit, - sort: Literal["date_asc", "date_desc"] | Omit = omit, - starting_on: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[AuditLogListResponse]: - """ - Get a comprehensive audit trail of all operations performed in your Metronome - account, whether initiated through the API, web interface, or automated - processes. This endpoint provides detailed logs of who did what and when, - enabling compliance reporting, security monitoring, and operational - troubleshooting across all interaction channels. - - ### Use this endpoint to: - - - Monitor all account activity for security and compliance purposes - - Track configuration changes regardless of source (API, UI, or system) - - Investigate issues by reviewing historical operations - - ### Key response fields: - - An array of AuditLog objects containing: - - - id: Unique identifier for the audit log entry - - timestamp: When the action occurred (RFC 3339 format) - - actor: Information about who performed the action - - request: Details including request ID, IP address, and user agent - - `resource_type`: The type of resource affected (e.g., customer, contract, - invoice) - - `resource_id`: The specific resource identifier - - `action`: The operation performed - - `next_page`: Cursor for continuous log retrieval - - ### Usage guidelines: - - - Continuous retrieval: The next_page token enables uninterrupted log - streaming—save it between requests to ensure no logs are missed - - Empty responses: An empty data array means no new logs yet; continue polling - with the same next_page token - - Date filtering: - - `starting_on`: Earliest logs to return (inclusive) - - `ending_before`: Latest logs to return (exclusive) - - Cannot be used with `next_page` - - Resource filtering: Must specify both `resource_type` and `resource_id` - together - - Sort order: Default is `date_asc`; use `date_desc` for newest first - - Args: - ending_before: RFC 3339 timestamp (exclusive). Cannot be used with 'next_page'. - - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - resource_id: Optional parameter that can be used to filter which audit logs are returned. If - you specify resource_id, you must also specify resource_type. - - resource_type: Optional parameter that can be used to filter which audit logs are returned. If - you specify resource_type, you must also specify resource_id. - - sort: Sort order by timestamp, e.g. date_asc or date_desc. Defaults to date_asc. - - starting_on: RFC 3339 timestamp of the earliest audit log to return. Cannot be used with - 'next_page'. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/auditLogs", - page=SyncCursorPage[AuditLogListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "ending_before": ending_before, - "limit": limit, - "next_page": next_page, - "resource_id": resource_id, - "resource_type": resource_type, - "sort": sort, - "starting_on": starting_on, - }, - audit_log_list_params.AuditLogListParams, - ), - ), - model=AuditLogListResponse, - ) - - -class AsyncAuditLogsResource(AsyncAPIResource): - """ - [Security](https://docs.metronome.com/developer-resources/security/) endpoints allow you to retrieve security-related data. - """ - - @cached_property - def with_raw_response(self) -> AsyncAuditLogsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncAuditLogsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncAuditLogsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncAuditLogsResourceWithStreamingResponse(self) - - def list( - self, - *, - ending_before: Union[str, datetime] | Omit = omit, - limit: int | Omit = omit, - next_page: str | Omit = omit, - resource_id: str | Omit = omit, - resource_type: str | Omit = omit, - sort: Literal["date_asc", "date_desc"] | Omit = omit, - starting_on: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[AuditLogListResponse, AsyncCursorPage[AuditLogListResponse]]: - """ - Get a comprehensive audit trail of all operations performed in your Metronome - account, whether initiated through the API, web interface, or automated - processes. This endpoint provides detailed logs of who did what and when, - enabling compliance reporting, security monitoring, and operational - troubleshooting across all interaction channels. - - ### Use this endpoint to: - - - Monitor all account activity for security and compliance purposes - - Track configuration changes regardless of source (API, UI, or system) - - Investigate issues by reviewing historical operations - - ### Key response fields: - - An array of AuditLog objects containing: - - - id: Unique identifier for the audit log entry - - timestamp: When the action occurred (RFC 3339 format) - - actor: Information about who performed the action - - request: Details including request ID, IP address, and user agent - - `resource_type`: The type of resource affected (e.g., customer, contract, - invoice) - - `resource_id`: The specific resource identifier - - `action`: The operation performed - - `next_page`: Cursor for continuous log retrieval - - ### Usage guidelines: - - - Continuous retrieval: The next_page token enables uninterrupted log - streaming—save it between requests to ensure no logs are missed - - Empty responses: An empty data array means no new logs yet; continue polling - with the same next_page token - - Date filtering: - - `starting_on`: Earliest logs to return (inclusive) - - `ending_before`: Latest logs to return (exclusive) - - Cannot be used with `next_page` - - Resource filtering: Must specify both `resource_type` and `resource_id` - together - - Sort order: Default is `date_asc`; use `date_desc` for newest first - - Args: - ending_before: RFC 3339 timestamp (exclusive). Cannot be used with 'next_page'. - - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - resource_id: Optional parameter that can be used to filter which audit logs are returned. If - you specify resource_id, you must also specify resource_type. - - resource_type: Optional parameter that can be used to filter which audit logs are returned. If - you specify resource_type, you must also specify resource_id. - - sort: Sort order by timestamp, e.g. date_asc or date_desc. Defaults to date_asc. - - starting_on: RFC 3339 timestamp of the earliest audit log to return. Cannot be used with - 'next_page'. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/auditLogs", - page=AsyncCursorPage[AuditLogListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "ending_before": ending_before, - "limit": limit, - "next_page": next_page, - "resource_id": resource_id, - "resource_type": resource_type, - "sort": sort, - "starting_on": starting_on, - }, - audit_log_list_params.AuditLogListParams, - ), - ), - model=AuditLogListResponse, - ) - - -class AuditLogsResourceWithRawResponse: - def __init__(self, audit_logs: AuditLogsResource) -> None: - self._audit_logs = audit_logs - - self.list = to_raw_response_wrapper( - audit_logs.list, - ) - - -class AsyncAuditLogsResourceWithRawResponse: - def __init__(self, audit_logs: AsyncAuditLogsResource) -> None: - self._audit_logs = audit_logs - - self.list = async_to_raw_response_wrapper( - audit_logs.list, - ) - - -class AuditLogsResourceWithStreamingResponse: - def __init__(self, audit_logs: AuditLogsResource) -> None: - self._audit_logs = audit_logs - - self.list = to_streamed_response_wrapper( - audit_logs.list, - ) - - -class AsyncAuditLogsResourceWithStreamingResponse: - def __init__(self, audit_logs: AsyncAuditLogsResource) -> None: - self._audit_logs = audit_logs - - self.list = async_to_streamed_response_wrapper( - audit_logs.list, - ) diff --git a/src/metronome/resources/v1/billable_metrics.py b/src/metronome/resources/v1/billable_metrics.py deleted file mode 100644 index 40ae0b2d8..000000000 --- a/src/metronome/resources/v1/billable_metrics.py +++ /dev/null @@ -1,636 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Iterable -from typing_extensions import Literal - -import httpx - -from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ...types.v1 import billable_metric_list_params, billable_metric_create_params, billable_metric_archive_params -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ...pagination import SyncCursorPage, AsyncCursorPage -from ..._base_client import AsyncPaginator, make_request_options -from ...types.shared_params.property_filter import PropertyFilter -from ...types.shared_params.event_type_filter import EventTypeFilter -from ...types.v1.billable_metric_list_response import BillableMetricListResponse -from ...types.v1.billable_metric_create_response import BillableMetricCreateResponse -from ...types.v1.billable_metric_archive_response import BillableMetricArchiveResponse -from ...types.v1.billable_metric_retrieve_response import BillableMetricRetrieveResponse - -__all__ = ["BillableMetricsResource", "AsyncBillableMetricsResource"] - - -class BillableMetricsResource(SyncAPIResource): - """ - [Billable metrics](https://docs.metronome.com/understanding-metronome/how-metronome-works#billable-metrics) in Metronome represent the various consumption components that Metronome meters and aggregates. - """ - - @cached_property - def with_raw_response(self) -> BillableMetricsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return BillableMetricsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> BillableMetricsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return BillableMetricsResourceWithStreamingResponse(self) - - def create( - self, - *, - name: str, - aggregation_key: str | Omit = omit, - aggregation_type: Literal["COUNT", "LATEST", "MAX", "SUM", "UNIQUE"] | Omit = omit, - custom_fields: Dict[str, str] | Omit = omit, - event_type_filter: EventTypeFilter | Omit = omit, - group_keys: Iterable[SequenceNotStr[str]] | Omit = omit, - property_filters: Iterable[PropertyFilter] | Omit = omit, - sql: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> BillableMetricCreateResponse: - """ - Create billable metrics programmatically with this endpoint—an essential step in - configuring your pricing and packaging in Metronome. - - A billable metric is a customizable query that filters and aggregates events - from your event stream. These metrics are continuously tracked as usage data - enters Metronome through the ingestion pipeline. The ingestion process - transforms raw usage data into actionable pricing metrics, enabling accurate - metering and billing for your products. - - ### Use this endpoint to: - - - Create individual or multiple billable metrics as part of a setup workflow. - - Automate the entire pricing configuration process, from metric creation to - customer contract setup. - - Define metrics using either standard filtering/aggregation or a custom SQL - query. - - ### Key response fields: - - - The ID of the billable metric that was created - - The created billable metric will be available to be used in Products, usage - endpoints, and alerts. - - ### Usage guidelines: - - - Metrics defined using standard filtering and aggregation are Streaming - billable metrics, which have been optimized for ultra low latency and high - throughput workflows. - - Use SQL billable metrics if you require more flexible aggregation options. - - Args: - name: The display name of the billable metric. - - aggregation_key: Specifies the type of aggregation performed on matching events. Required if - `sql` is not provided. - - aggregation_type: Specifies the type of aggregation performed on matching events. - - custom_fields: Custom fields to attach to the billable metric. - - event_type_filter: An optional filtering rule to match the 'event_type' property of an event. - - group_keys: Property names that are used to group usage costs on an invoice. Each entry - represents a set of properties used to slice events into distinct buckets. - - property_filters: A list of filters to match events to this billable metric. Each filter defines a - rule on an event property. All rules must pass for the event to match the - billable metric. - - sql: The SQL query associated with the billable metric. This field is mutually - exclusive with aggregation_type, event_type_filter, property_filters, - aggregation_key, and group_keys. If provided, these other fields must be - omitted. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/billable-metrics/create", - body=maybe_transform( - { - "name": name, - "aggregation_key": aggregation_key, - "aggregation_type": aggregation_type, - "custom_fields": custom_fields, - "event_type_filter": event_type_filter, - "group_keys": group_keys, - "property_filters": property_filters, - "sql": sql, - }, - billable_metric_create_params.BillableMetricCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=BillableMetricCreateResponse, - ) - - def retrieve( - self, - *, - billable_metric_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> BillableMetricRetrieveResponse: - """ - Retrieves the complete configuration for a specific billable metric by its ID. - Use this to review billable metric setup before associating it with products. - Returns the metric's `name`, `event_type_filter`, `property_filters`, - `aggregation_type`, `aggregation_key`, `group_keys`, `custom fields`, and - `SQL query` (if it's a SQL billable metric). - - Important: - - - Archived billable metrics will include an `archived_at` timestamp; they no - longer process new usage events but remain accessible for historical - reference. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not billable_metric_id: - raise ValueError(f"Expected a non-empty value for `billable_metric_id` but received {billable_metric_id!r}") - return self._get( - f"/v1/billable-metrics/{billable_metric_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=BillableMetricRetrieveResponse, - ) - - def list( - self, - *, - include_archived: bool | Omit = omit, - limit: int | Omit = omit, - next_page: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[BillableMetricListResponse]: - """Retrieves all billable metrics with their complete configurations. - - Use this for - programmatic discovery and management of billable metrics, such as associating - metrics to products and auditing for orphaned or archived metrics. Important: - Archived metrics are excluded by default; use `include_archived`=`true` - parameter to include them. - - Args: - include_archived: If true, the list of returned metrics will include archived metrics - - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/billable-metrics", - page=SyncCursorPage[BillableMetricListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "include_archived": include_archived, - "limit": limit, - "next_page": next_page, - }, - billable_metric_list_params.BillableMetricListParams, - ), - ), - model=BillableMetricListResponse, - ) - - def archive( - self, - *, - id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> BillableMetricArchiveResponse: - """Use this endpoint to retire billable metrics that are no longer used. - - After a - billable metric is archived, that billable metric can no longer be used in any - new Products to define how that product should be metered. If you archive a - billable metric that is already associated with a Product, the Product will - continue to function as usual, metering based on the definition of the archived - billable metric. - - Archived billable metrics will be returned on the `getBillableMetric` and - `listBillableMetrics` endpoints with a populated `archived_at` field. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/billable-metrics/archive", - body=maybe_transform({"id": id}, billable_metric_archive_params.BillableMetricArchiveParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=BillableMetricArchiveResponse, - ) - - -class AsyncBillableMetricsResource(AsyncAPIResource): - """ - [Billable metrics](https://docs.metronome.com/understanding-metronome/how-metronome-works#billable-metrics) in Metronome represent the various consumption components that Metronome meters and aggregates. - """ - - @cached_property - def with_raw_response(self) -> AsyncBillableMetricsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncBillableMetricsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncBillableMetricsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncBillableMetricsResourceWithStreamingResponse(self) - - async def create( - self, - *, - name: str, - aggregation_key: str | Omit = omit, - aggregation_type: Literal["COUNT", "LATEST", "MAX", "SUM", "UNIQUE"] | Omit = omit, - custom_fields: Dict[str, str] | Omit = omit, - event_type_filter: EventTypeFilter | Omit = omit, - group_keys: Iterable[SequenceNotStr[str]] | Omit = omit, - property_filters: Iterable[PropertyFilter] | Omit = omit, - sql: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> BillableMetricCreateResponse: - """ - Create billable metrics programmatically with this endpoint—an essential step in - configuring your pricing and packaging in Metronome. - - A billable metric is a customizable query that filters and aggregates events - from your event stream. These metrics are continuously tracked as usage data - enters Metronome through the ingestion pipeline. The ingestion process - transforms raw usage data into actionable pricing metrics, enabling accurate - metering and billing for your products. - - ### Use this endpoint to: - - - Create individual or multiple billable metrics as part of a setup workflow. - - Automate the entire pricing configuration process, from metric creation to - customer contract setup. - - Define metrics using either standard filtering/aggregation or a custom SQL - query. - - ### Key response fields: - - - The ID of the billable metric that was created - - The created billable metric will be available to be used in Products, usage - endpoints, and alerts. - - ### Usage guidelines: - - - Metrics defined using standard filtering and aggregation are Streaming - billable metrics, which have been optimized for ultra low latency and high - throughput workflows. - - Use SQL billable metrics if you require more flexible aggregation options. - - Args: - name: The display name of the billable metric. - - aggregation_key: Specifies the type of aggregation performed on matching events. Required if - `sql` is not provided. - - aggregation_type: Specifies the type of aggregation performed on matching events. - - custom_fields: Custom fields to attach to the billable metric. - - event_type_filter: An optional filtering rule to match the 'event_type' property of an event. - - group_keys: Property names that are used to group usage costs on an invoice. Each entry - represents a set of properties used to slice events into distinct buckets. - - property_filters: A list of filters to match events to this billable metric. Each filter defines a - rule on an event property. All rules must pass for the event to match the - billable metric. - - sql: The SQL query associated with the billable metric. This field is mutually - exclusive with aggregation_type, event_type_filter, property_filters, - aggregation_key, and group_keys. If provided, these other fields must be - omitted. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/billable-metrics/create", - body=await async_maybe_transform( - { - "name": name, - "aggregation_key": aggregation_key, - "aggregation_type": aggregation_type, - "custom_fields": custom_fields, - "event_type_filter": event_type_filter, - "group_keys": group_keys, - "property_filters": property_filters, - "sql": sql, - }, - billable_metric_create_params.BillableMetricCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=BillableMetricCreateResponse, - ) - - async def retrieve( - self, - *, - billable_metric_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> BillableMetricRetrieveResponse: - """ - Retrieves the complete configuration for a specific billable metric by its ID. - Use this to review billable metric setup before associating it with products. - Returns the metric's `name`, `event_type_filter`, `property_filters`, - `aggregation_type`, `aggregation_key`, `group_keys`, `custom fields`, and - `SQL query` (if it's a SQL billable metric). - - Important: - - - Archived billable metrics will include an `archived_at` timestamp; they no - longer process new usage events but remain accessible for historical - reference. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not billable_metric_id: - raise ValueError(f"Expected a non-empty value for `billable_metric_id` but received {billable_metric_id!r}") - return await self._get( - f"/v1/billable-metrics/{billable_metric_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=BillableMetricRetrieveResponse, - ) - - def list( - self, - *, - include_archived: bool | Omit = omit, - limit: int | Omit = omit, - next_page: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[BillableMetricListResponse, AsyncCursorPage[BillableMetricListResponse]]: - """Retrieves all billable metrics with their complete configurations. - - Use this for - programmatic discovery and management of billable metrics, such as associating - metrics to products and auditing for orphaned or archived metrics. Important: - Archived metrics are excluded by default; use `include_archived`=`true` - parameter to include them. - - Args: - include_archived: If true, the list of returned metrics will include archived metrics - - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/billable-metrics", - page=AsyncCursorPage[BillableMetricListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "include_archived": include_archived, - "limit": limit, - "next_page": next_page, - }, - billable_metric_list_params.BillableMetricListParams, - ), - ), - model=BillableMetricListResponse, - ) - - async def archive( - self, - *, - id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> BillableMetricArchiveResponse: - """Use this endpoint to retire billable metrics that are no longer used. - - After a - billable metric is archived, that billable metric can no longer be used in any - new Products to define how that product should be metered. If you archive a - billable metric that is already associated with a Product, the Product will - continue to function as usual, metering based on the definition of the archived - billable metric. - - Archived billable metrics will be returned on the `getBillableMetric` and - `listBillableMetrics` endpoints with a populated `archived_at` field. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/billable-metrics/archive", - body=await async_maybe_transform({"id": id}, billable_metric_archive_params.BillableMetricArchiveParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=BillableMetricArchiveResponse, - ) - - -class BillableMetricsResourceWithRawResponse: - def __init__(self, billable_metrics: BillableMetricsResource) -> None: - self._billable_metrics = billable_metrics - - self.create = to_raw_response_wrapper( - billable_metrics.create, - ) - self.retrieve = to_raw_response_wrapper( - billable_metrics.retrieve, - ) - self.list = to_raw_response_wrapper( - billable_metrics.list, - ) - self.archive = to_raw_response_wrapper( - billable_metrics.archive, - ) - - -class AsyncBillableMetricsResourceWithRawResponse: - def __init__(self, billable_metrics: AsyncBillableMetricsResource) -> None: - self._billable_metrics = billable_metrics - - self.create = async_to_raw_response_wrapper( - billable_metrics.create, - ) - self.retrieve = async_to_raw_response_wrapper( - billable_metrics.retrieve, - ) - self.list = async_to_raw_response_wrapper( - billable_metrics.list, - ) - self.archive = async_to_raw_response_wrapper( - billable_metrics.archive, - ) - - -class BillableMetricsResourceWithStreamingResponse: - def __init__(self, billable_metrics: BillableMetricsResource) -> None: - self._billable_metrics = billable_metrics - - self.create = to_streamed_response_wrapper( - billable_metrics.create, - ) - self.retrieve = to_streamed_response_wrapper( - billable_metrics.retrieve, - ) - self.list = to_streamed_response_wrapper( - billable_metrics.list, - ) - self.archive = to_streamed_response_wrapper( - billable_metrics.archive, - ) - - -class AsyncBillableMetricsResourceWithStreamingResponse: - def __init__(self, billable_metrics: AsyncBillableMetricsResource) -> None: - self._billable_metrics = billable_metrics - - self.create = async_to_streamed_response_wrapper( - billable_metrics.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - billable_metrics.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - billable_metrics.list, - ) - self.archive = async_to_streamed_response_wrapper( - billable_metrics.archive, - ) diff --git a/src/metronome/resources/v1/contracts/__init__.py b/src/metronome/resources/v1/contracts/__init__.py deleted file mode 100644 index 1d2eece87..000000000 --- a/src/metronome/resources/v1/contracts/__init__.py +++ /dev/null @@ -1,61 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .products import ( - ProductsResource, - AsyncProductsResource, - ProductsResourceWithRawResponse, - AsyncProductsResourceWithRawResponse, - ProductsResourceWithStreamingResponse, - AsyncProductsResourceWithStreamingResponse, -) -from .contracts import ( - ContractsResource, - AsyncContractsResource, - ContractsResourceWithRawResponse, - AsyncContractsResourceWithRawResponse, - ContractsResourceWithStreamingResponse, - AsyncContractsResourceWithStreamingResponse, -) -from .rate_cards import ( - RateCardsResource, - AsyncRateCardsResource, - RateCardsResourceWithRawResponse, - AsyncRateCardsResourceWithRawResponse, - RateCardsResourceWithStreamingResponse, - AsyncRateCardsResourceWithStreamingResponse, -) -from .named_schedules import ( - NamedSchedulesResource, - AsyncNamedSchedulesResource, - NamedSchedulesResourceWithRawResponse, - AsyncNamedSchedulesResourceWithRawResponse, - NamedSchedulesResourceWithStreamingResponse, - AsyncNamedSchedulesResourceWithStreamingResponse, -) - -__all__ = [ - "ProductsResource", - "AsyncProductsResource", - "ProductsResourceWithRawResponse", - "AsyncProductsResourceWithRawResponse", - "ProductsResourceWithStreamingResponse", - "AsyncProductsResourceWithStreamingResponse", - "RateCardsResource", - "AsyncRateCardsResource", - "RateCardsResourceWithRawResponse", - "AsyncRateCardsResourceWithRawResponse", - "RateCardsResourceWithStreamingResponse", - "AsyncRateCardsResourceWithStreamingResponse", - "NamedSchedulesResource", - "AsyncNamedSchedulesResource", - "NamedSchedulesResourceWithRawResponse", - "AsyncNamedSchedulesResourceWithRawResponse", - "NamedSchedulesResourceWithStreamingResponse", - "AsyncNamedSchedulesResourceWithStreamingResponse", - "ContractsResource", - "AsyncContractsResource", - "ContractsResourceWithRawResponse", - "AsyncContractsResourceWithRawResponse", - "ContractsResourceWithStreamingResponse", - "AsyncContractsResourceWithStreamingResponse", -] diff --git a/src/metronome/resources/v1/contracts/contracts.py b/src/metronome/resources/v1/contracts/contracts.py deleted file mode 100644 index 2fb76df91..000000000 --- a/src/metronome/resources/v1/contracts/contracts.py +++ /dev/null @@ -1,2840 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Any, Dict, Union, Iterable, cast -from datetime import datetime -from typing_extensions import Literal - -import httpx - -from .products import ( - ProductsResource, - AsyncProductsResource, - ProductsResourceWithRawResponse, - AsyncProductsResourceWithRawResponse, - ProductsResourceWithStreamingResponse, - AsyncProductsResourceWithStreamingResponse, -) -from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform -from ...._compat import cached_property -from ....types.v1 import ( - contract_list_params, - contract_amend_params, - contract_create_params, - contract_archive_params, - contract_retrieve_params, - contract_list_balances_params, - contract_get_net_balance_params, - contract_update_end_date_params, - contract_set_usage_filter_params, - contract_retrieve_rate_schedule_params, - contract_add_manual_balance_entry_params, - contract_create_historical_invoices_params, - contract_schedule_pro_services_invoice_params, - contract_retrieve_subscription_quantity_history_params, -) -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ....pagination import SyncBodyCursorPage, AsyncBodyCursorPage -from ...._base_client import AsyncPaginator, make_request_options -from .named_schedules import ( - NamedSchedulesResource, - AsyncNamedSchedulesResource, - NamedSchedulesResourceWithRawResponse, - AsyncNamedSchedulesResourceWithRawResponse, - NamedSchedulesResourceWithStreamingResponse, - AsyncNamedSchedulesResourceWithStreamingResponse, -) -from .rate_cards.rate_cards import ( - RateCardsResource, - AsyncRateCardsResource, - RateCardsResourceWithRawResponse, - AsyncRateCardsResourceWithRawResponse, - RateCardsResourceWithStreamingResponse, - AsyncRateCardsResourceWithStreamingResponse, -) -from ....types.v1.contract_list_response import ContractListResponse -from ....types.v1.contract_amend_response import ContractAmendResponse -from ....types.v1.contract_create_response import ContractCreateResponse -from ....types.shared_params.balance_filter import BalanceFilter -from ....types.v1.contract_archive_response import ContractArchiveResponse -from ....types.v1.contract_retrieve_response import ContractRetrieveResponse -from ....types.shared_params.base_usage_filter import BaseUsageFilter -from ....types.v1.contract_list_balances_response import ContractListBalancesResponse -from ....types.v1.contract_get_net_balance_response import ContractGetNetBalanceResponse -from ....types.v1.contract_update_end_date_response import ContractUpdateEndDateResponse -from ....types.shared_params.spend_threshold_configuration import SpendThresholdConfiguration -from ....types.v1.contract_retrieve_rate_schedule_response import ContractRetrieveRateScheduleResponse -from ....types.v1.contract_create_historical_invoices_response import ContractCreateHistoricalInvoicesResponse -from ....types.v1.contract_schedule_pro_services_invoice_response import ContractScheduleProServicesInvoiceResponse -from ....types.shared_params.prepaid_balance_threshold_configuration import PrepaidBalanceThresholdConfiguration -from ....types.v1.contract_retrieve_subscription_quantity_history_response import ( - ContractRetrieveSubscriptionQuantityHistoryResponse, -) - -__all__ = ["ContractsResource", "AsyncContractsResource"] - - -class ContractsResource(SyncAPIResource): - @cached_property - def products(self) -> ProductsResource: - """Products are the items that customers purchase.""" - return ProductsResource(self._client) - - @cached_property - def rate_cards(self) -> RateCardsResource: - """Rate cards are used to define default pricing for products.""" - return RateCardsResource(self._client) - - @cached_property - def named_schedules(self) -> NamedSchedulesResource: - """Named schedules are used for storing custom data that can change over time. - - Named schedules are often used in custom pricing logic. - """ - return NamedSchedulesResource(self._client) - - @cached_property - def with_raw_response(self) -> ContractsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return ContractsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ContractsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return ContractsResourceWithStreamingResponse(self) - - def create( - self, - *, - customer_id: str, - starting_at: Union[str, datetime], - billing_provider_configuration: contract_create_params.BillingProviderConfiguration | Omit = omit, - commits: Iterable[contract_create_params.Commit] | Omit = omit, - credits: Iterable[contract_create_params.Credit] | Omit = omit, - custom_fields: Dict[str, str] | Omit = omit, - discounts: Iterable[contract_create_params.Discount] | Omit = omit, - ending_before: Union[str, datetime] | Omit = omit, - hierarchy_configuration: contract_create_params.HierarchyConfiguration | Omit = omit, - multiplier_override_prioritization: Literal["LOWEST_MULTIPLIER", "EXPLICIT"] | Omit = omit, - name: str | Omit = omit, - net_payment_terms_days: float | Omit = omit, - netsuite_sales_order_id: str | Omit = omit, - overrides: Iterable[contract_create_params.Override] | Omit = omit, - package_alias: str | Omit = omit, - package_id: str | Omit = omit, - prepaid_balance_threshold_configuration: PrepaidBalanceThresholdConfiguration | Omit = omit, - professional_services: Iterable[contract_create_params.ProfessionalService] | Omit = omit, - rate_card_alias: str | Omit = omit, - rate_card_id: str | Omit = omit, - recurring_commits: Iterable[contract_create_params.RecurringCommit] | Omit = omit, - recurring_credits: Iterable[contract_create_params.RecurringCredit] | Omit = omit, - reseller_royalties: Iterable[contract_create_params.ResellerRoyalty] | Omit = omit, - revenue_system_configuration: contract_create_params.RevenueSystemConfiguration | Omit = omit, - salesforce_opportunity_id: str | Omit = omit, - scheduled_charges: Iterable[contract_create_params.ScheduledCharge] | Omit = omit, - scheduled_charges_on_usage_invoices: Literal["ALL"] | Omit = omit, - spend_threshold_configuration: SpendThresholdConfiguration | Omit = omit, - subscriptions: Iterable[contract_create_params.Subscription] | Omit = omit, - total_contract_value: float | Omit = omit, - transition: contract_create_params.Transition | Omit = omit, - uniqueness_key: str | Omit = omit, - usage_filter: BaseUsageFilter | Omit = omit, - usage_statement_schedule: contract_create_params.UsageStatementSchedule | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractCreateResponse: - """ - Contracts define a customer's products, pricing, discounts, access duration, and - billing configuration. Contracts serve as the central billing agreement for both - PLG and Enterprise customers, you can automatically customers access to your - products and services directly from your product or CRM. - - ### Use this endpoint to: - - - PLG onboarding: Automatically provision new self-serve customers with - contracts when they sign up. - - Enterprise sales: Push negotiated contracts from Salesforce with custom - pricing and commitments - - Promotional pricing: Implement time-limited discounts and free trials through - overrides - - ### Key components: - - #### Contract Term and Billing Schedule - - - Set contract duration using `starting_at` and `ending_before` fields. PLG - contracts typically use perpetual agreements (no end date), while Enterprise - contracts have fixed end dates which can be edited over time in the case of - co-term upsells. - - #### Rate Card - - If you are offering usage based pricing, you can set a rate card for the - contract to reference through `rate_card_id` or `rate_card_alias`. The rate card - is a store of all of your usage based products and their centralized pricing. - Any new products or price changes on the rate card can be set to automatically - propagate to all associated contracts - this ensures consistent pricing and - product launches flow to contracts without manual updates and migrations. The - `usage_statement_schedule` determines the cadence on which Metronome will - finalize a usage invoice for the customer. This defaults to monthly on the 1st, - with options for custom dates, quarterly, or annual cadences. Note: Most usage - based billing companies align usage statements to be evaluated aligned to the - first of the month. Read more about - [Rate Cards](https://docs.metronome.com/pricing-packaging/create-manage-rate-cards/). - - #### Overrides and discounts - - Customize pricing on the contract through time-bounded overrides that can target - specific products, product families, or complex usage scenarios. Overrides - enable two key capabilities: - - - Discounts: Apply percentage discounts, fixed rate reductions, or - quantity-based pricing tiers - - Entitlements: Provide special pricing or access to specific products for - negotiated deals - - Read more about - [Contract Overrides](https://docs.metronome.com/manage-product-access/add-contract-override/). - - #### Commits and Credits - - Using commits, configure prepaid or postpaid spending commitments where - customers promise to spend a certain amount over the contract period paid in - advance or in arrears. Use credits to provide free spending allowances. Under - the hood these are the same mechanisms, however, credits are typically offered - for free (SLA or promotional) or as a part of an allotment associated with a - Subscription. - - In Metronome, you can set commits and credits to only be applicable for a subset - of usage. Use `applicable_product_ids` or `applicable_product_tags` to create - product or product-family specific commits or credits, or you can build complex - boolean logic specifiers to target usage based on pricing and presentation group - values using `override_specifiers`. - - These objects can also also be configured to have a recurrence schedule to - easily model customer packaging which includes recurring monthly or quarterly - allotments. - - Commits support rollover settings (`rollover_fraction`) to transfer unused - balances between contract periods, either entirely or as a percentage. - - Read more about - [Credits and Commits](https://docs.metronome.com/pricing-packaging/apply-credits-commits/). - - #### Subscriptions - - You can add a fixed recurring charge to a contract, like monthly licenses or - seat-based fees, using the subscription charge. Subscription charges are defined - on your rate card and you can select which subscription is applicable to add to - each contract. When you add a subscription to a contract you need to: - - - Define whether the subscription is paid for in-advance or in-arrears - (`collection_schedule`) - - Define the proration behavior (`proration`) - - Specify an initial quantity (`initial_quantity`) - - Define which subscription rate on the rate card should be used - (`subscription_rate`) - - Read more about - [Subscriptions](https://docs.metronome.com/manage-product-access/create-subscription/). - - #### Scheduled Charges - - Set up one-time, recurring, or entirely custom charges that occur on specific - dates, separate from usage-based billing or commitments. These can be used to - model non-recurring platform charges or professional services. - - #### Threshold Billing - - Metronome allows you to configure automatic billing triggers when customers - reach spending thresholds to prevent fraud and manage risk. You can use - `spend_threshold_configuration` to trigger an invoice to cover current charges - whenever the threshold is reached or you can ensure the customer maintains a - minimum prepaid balance using the `prepaid_balance_configuration`. - - Read more about - [Spend Threshold](https://docs.metronome.com/manage-product-access/spend-thresholds/) - and - [Prepaid Balance Thresholds](https://docs.metronome.com/manage-product-access/prepaid-balance-thresholds/). - - ### Usage guidelines: - - - You can always - [Edit Contracts](https://docs.metronome.com/manage-product-access/edit-contract/) - after it has been created, using the `editContract` endpoint. Metronome keeps - track of all edits, both in the audit log and over the `getEditHistory` - endpoint. - - Customers in Metronome can have multiple concurrent contracts at one time. Use - `usage_filters` to route the correct usage to each contract. - [Read more about usage filters](https://docs.metronome.com/manage-product-access/provision-customer/#create-a-usage-filter). - - Args: - starting_at: inclusive contract start time - - billing_provider_configuration: The billing provider configuration associated with a contract. Provide either an - ID or the provider and delivery method. - - custom_fields: Custom fields to be added eg. { "key1": "value1", "key2": "value2" } - - discounts: This field's availability is dependent on your client's configuration. - - ending_before: exclusive contract end time - - multiplier_override_prioritization: Defaults to LOWEST_MULTIPLIER, which applies the greatest discount to list - prices automatically. EXPLICIT prioritization requires specifying priorities for - each multiplier; the one with the lowest priority value will be prioritized - first. If tiered overrides are used, prioritization must be explicit. - - netsuite_sales_order_id: This field's availability is dependent on your client's configuration. - - package_alias: Selects the package linked to the specified alias as of the contract's start - date. Mutually exclusive with package_id. - - package_id: If provided, provisions a customer on a package instead of creating a - traditional contract. When specified, only customer_id, starting_at, package_id, - and uniqueness_key are allowed. - - professional_services: This field's availability is dependent on your client's configuration. - - rate_card_alias: Selects the rate card linked to the specified alias as of the contract's start - date. - - reseller_royalties: This field's availability is dependent on your client's configuration. - - revenue_system_configuration: The revenue system configuration associated with a contract. Provide either an - ID or the provider and delivery method. - - salesforce_opportunity_id: This field's availability is dependent on your client's configuration. - - scheduled_charges_on_usage_invoices: Determines which scheduled and commit charges to consolidate onto the Contract's - usage invoice. The charge's `timestamp` must match the usage invoice's - `ending_before` date for consolidation to occur. This field cannot be modified - after a Contract has been created. If this field is omitted, charges will appear - on a separate invoice from usage charges. - - subscriptions: Optional list of - [subscriptions](https://docs.metronome.com/manage-product-access/create-subscription/) - to add to the contract. - - total_contract_value: This field's availability is dependent on your client's configuration. - - uniqueness_key: Prevents the creation of duplicates. If a request to create a record is made - with a previously used uniqueness key, a new record will not be created and the - request will fail with a 409 error. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contracts/create", - body=maybe_transform( - { - "customer_id": customer_id, - "starting_at": starting_at, - "billing_provider_configuration": billing_provider_configuration, - "commits": commits, - "credits": credits, - "custom_fields": custom_fields, - "discounts": discounts, - "ending_before": ending_before, - "hierarchy_configuration": hierarchy_configuration, - "multiplier_override_prioritization": multiplier_override_prioritization, - "name": name, - "net_payment_terms_days": net_payment_terms_days, - "netsuite_sales_order_id": netsuite_sales_order_id, - "overrides": overrides, - "package_alias": package_alias, - "package_id": package_id, - "prepaid_balance_threshold_configuration": prepaid_balance_threshold_configuration, - "professional_services": professional_services, - "rate_card_alias": rate_card_alias, - "rate_card_id": rate_card_id, - "recurring_commits": recurring_commits, - "recurring_credits": recurring_credits, - "reseller_royalties": reseller_royalties, - "revenue_system_configuration": revenue_system_configuration, - "salesforce_opportunity_id": salesforce_opportunity_id, - "scheduled_charges": scheduled_charges, - "scheduled_charges_on_usage_invoices": scheduled_charges_on_usage_invoices, - "spend_threshold_configuration": spend_threshold_configuration, - "subscriptions": subscriptions, - "total_contract_value": total_contract_value, - "transition": transition, - "uniqueness_key": uniqueness_key, - "usage_filter": usage_filter, - "usage_statement_schedule": usage_statement_schedule, - }, - contract_create_params.ContractCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractCreateResponse, - ) - - def retrieve( - self, - *, - contract_id: str, - customer_id: str, - include_balance: bool | Omit = omit, - include_ledgers: bool | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractRetrieveResponse: - """This is the v1 endpoint to get a contract. - - New clients should implement using - the v2 endpoint. - - Args: - include_balance: Include the balance of credits and commits in the response. Setting this flag - may cause the query to be slower. - - include_ledgers: Include commit ledgers in the response. Setting this flag may cause the query to - be slower. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contracts/get", - body=maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - "include_balance": include_balance, - "include_ledgers": include_ledgers, - }, - contract_retrieve_params.ContractRetrieveParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractRetrieveResponse, - ) - - def list( - self, - *, - customer_id: str, - covering_date: Union[str, datetime] | Omit = omit, - include_archived: bool | Omit = omit, - include_balance: bool | Omit = omit, - include_ledgers: bool | Omit = omit, - starting_at: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractListResponse: - """ - Retrieves all contracts for a specific customer, including pricing, terms, - credits, and commitments. Use this to view a customer's contract history and - current agreements for billing management. Returns contract details with - optional ledgers and balance information. - - ⚠️ Note: This is the legacy v1 endpoint - new integrations should use the v2 - endpoint for enhanced features. - - Args: - covering_date: Optional RFC 3339 timestamp. If provided, the response will include only - contracts effective on the provided date. This cannot be provided if the - starting_at filter is provided. - - include_archived: Include archived contracts in the response - - include_balance: Include the balance of credits and commits in the response. Setting this flag - may cause the query to be slower. - - include_ledgers: Include commit ledgers in the response. Setting this flag may cause the query to - be slower. - - starting_at: Optional RFC 3339 timestamp. If provided, the response will include only - contracts where effective_at is on or after the provided date. This cannot be - provided if the covering_date filter is provided. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contracts/list", - body=maybe_transform( - { - "customer_id": customer_id, - "covering_date": covering_date, - "include_archived": include_archived, - "include_balance": include_balance, - "include_ledgers": include_ledgers, - "starting_at": starting_at, - }, - contract_list_params.ContractListParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractListResponse, - ) - - def add_manual_balance_entry( - self, - *, - id: str, - amount: float, - customer_id: str, - reason: str, - segment_id: str, - contract_id: str | Omit = omit, - per_group_amounts: Dict[str, float] | Omit = omit, - timestamp: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """Manually adjust the available balance on a commit or credit. - - This entry is - appended to the commit ledger as a new event. Optionally include a description - that provides the reasoning for the entry. - - ### Use this endpoint to: - - - Address incorrect usage burn-down caused by malformed usage or invalid config - - Decrease available balance to account for outages where usage may have not - been tracked or sent to Metronome - - Issue credits to customers in the form of increased balance on existing commit - or credit - - ### Usage guidelines: - - Manual ledger entries can be extremely useful for resolving discrepancies in - Metronome. However, most corrections to inaccurate billings can be modified - upstream of the commit, whether that is via contract editing, rate editing, or - other actions that cause an invoice to be recalculated. - - Args: - id: ID of the balance (commit or credit) to update. - - amount: Amount to add to the segment. A negative number will draw down from the balance. - - customer_id: ID of the customer whose balance is to be updated. - - reason: Reason for the manual adjustment. This will be displayed in the ledger. - - segment_id: ID of the segment to update. - - contract_id: ID of the contract to update. Leave blank to update a customer level balance. - - per_group_amounts: If using individually configured commits/credits attached to seat managed - subscriptions, the amount to add for each seat. Must sum to total amount. - - timestamp: RFC 3339 timestamp indicating when the manual adjustment takes place. If not - provided, it will default to the start of the segment. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._post( - "/v1/contracts/addManualBalanceLedgerEntry", - body=maybe_transform( - { - "id": id, - "amount": amount, - "customer_id": customer_id, - "reason": reason, - "segment_id": segment_id, - "contract_id": contract_id, - "per_group_amounts": per_group_amounts, - "timestamp": timestamp, - }, - contract_add_manual_balance_entry_params.ContractAddManualBalanceEntryParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def amend( - self, - *, - contract_id: str, - customer_id: str, - starting_at: Union[str, datetime], - commits: Iterable[contract_amend_params.Commit] | Omit = omit, - credits: Iterable[contract_amend_params.Credit] | Omit = omit, - custom_fields: Dict[str, str] | Omit = omit, - discounts: Iterable[contract_amend_params.Discount] | Omit = omit, - netsuite_sales_order_id: str | Omit = omit, - overrides: Iterable[contract_amend_params.Override] | Omit = omit, - professional_services: Iterable[contract_amend_params.ProfessionalService] | Omit = omit, - reseller_royalties: Iterable[contract_amend_params.ResellerRoyalty] | Omit = omit, - salesforce_opportunity_id: str | Omit = omit, - scheduled_charges: Iterable[contract_amend_params.ScheduledCharge] | Omit = omit, - total_contract_value: float | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractAmendResponse: - """Amendments will be replaced by Contract editing. - - New clients should implement - using the `editContract` endpoint. Read more about the migration to contract - editing [here](/guides/implement-metronome/migrate-amendments-to-edits/) and - reach out to your Metronome representative for more details. Once contract - editing is enabled, access to this endpoint will be removed. - - Args: - contract_id: ID of the contract to amend - - customer_id: ID of the customer whose contract is to be amended - - starting_at: inclusive start time for the amendment - - custom_fields: Custom fields to be added eg. { "key1": "value1", "key2": "value2" } - - discounts: This field's availability is dependent on your client's configuration. - - netsuite_sales_order_id: This field's availability is dependent on your client's configuration. - - professional_services: This field's availability is dependent on your client's configuration. - - reseller_royalties: This field's availability is dependent on your client's configuration. - - salesforce_opportunity_id: This field's availability is dependent on your client's configuration. - - total_contract_value: This field's availability is dependent on your client's configuration. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contracts/amend", - body=maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - "starting_at": starting_at, - "commits": commits, - "credits": credits, - "custom_fields": custom_fields, - "discounts": discounts, - "netsuite_sales_order_id": netsuite_sales_order_id, - "overrides": overrides, - "professional_services": professional_services, - "reseller_royalties": reseller_royalties, - "salesforce_opportunity_id": salesforce_opportunity_id, - "scheduled_charges": scheduled_charges, - "total_contract_value": total_contract_value, - }, - contract_amend_params.ContractAmendParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractAmendResponse, - ) - - def archive( - self, - *, - contract_id: str, - customer_id: str, - void_invoices: bool, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractArchiveResponse: - """Permanently end and archive a contract along with all its terms. - - Any draft - invoices will be canceled, and all upcoming scheduled invoices will be - voided–also all finalized invoices can optionally be voided. Use this in the - event a contract was incorrectly created and needed to be removed from a - customer. - - #### Impact on commits and credits: - - When archiving a contract, all associated commits and credits are also archived. - For prepaid commits with active segments, Metronome automatically generates - expiration ledger entries to close out any remaining balances, ensuring accurate - accounting of unused prepaid amounts. These ledger entries will appear in the - commit's transaction history with type `PREPAID_COMMIT_EXPIRATION`. - - #### Archived contract visibility: - - Archived contracts remain accessible for historical reporting and audit - purposes. They can be retrieved using the `ListContracts` endpoint by setting - the `include_archived` parameter to `true` or in the Metronome UI when the "Show - archived" option is enabled. - - Args: - contract_id: ID of the contract to archive - - customer_id: ID of the customer whose contract is to be archived - - void_invoices: If false, the existing finalized invoices will remain after the contract is - archived. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contracts/archive", - body=maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - "void_invoices": void_invoices, - }, - contract_archive_params.ContractArchiveParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractArchiveResponse, - ) - - def create_historical_invoices( - self, - *, - invoices: Iterable[contract_create_historical_invoices_params.Invoice], - preview: bool, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractCreateHistoricalInvoicesResponse: - """ - Create historical usage invoices for past billing periods on specific contracts. - Use this endpoint to generate retroactive invoices with custom usage line items, - quantities, and date ranges. Supports preview mode to validate invoice data - before creation. Ideal for billing migrations or correcting past billing - periods. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contracts/createHistoricalInvoices", - body=maybe_transform( - { - "invoices": invoices, - "preview": preview, - }, - contract_create_historical_invoices_params.ContractCreateHistoricalInvoicesParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractCreateHistoricalInvoicesResponse, - ) - - def get_net_balance( - self, - *, - customer_id: str, - credit_type_id: str | Omit = omit, - filters: Iterable[BalanceFilter] | Omit = omit, - invoice_inclusion_mode: Literal["FINALIZED", "FINALIZED_AND_DRAFT"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractGetNetBalanceResponse: - """ - Retrieve the combined current balance across any grouping of credits and commits - for a customer in a single API call. - - - Display real-time available balance to customers in billing dashboards - - Build finance dashboards showing credit utilization across customer segments - - Validate expected vs. actual balance during billing reconciliation - - ### Key response fields: - - - `balance`: The combined net balance available to use at this moment across all - matching commits and credits - - `credit_type_id`: The credit type (fiat or custom pricing unit) the balance is - denominated in - - ### Filtering options: - - Balance filters allow you to scope the calculation to specific subsets of - commits and credits. When using multiple filter objects, they are OR'd together - — if a commit or credit matches any filter, it's included in the net balance. - Within a single filter object, all specified conditions are AND'd together. - - - **Balance types**: Include any combination of `PREPAID_COMMIT`, - `POSTPAID_COMMIT`, and `CREDIT` (e.g., `["PREPAID_COMMIT", "CREDIT"]` to - exclude postpaid commits). If not specified, all balance types are included. - - **Specific IDs**: Target exact commit or credit IDs for precise balance - queries - - **Custom fields**: Filter by custom field key-value pairs; when multiple pairs - are provided, commits must match all of them - - **Example**: To get the balance of all free-trial credits OR all - signup-promotion commits, you'd pass two filter objects — one filtering for - CREDIT with custom field campaign: free-trial, and another filtering for - PREPAID_COMMIT with custom field campaign: signup-promotion. - - ### Usage guidelines: - - - **Draft invoice handling**: Use `invoice_inclusion_mode` to control whether - pending draft invoice deductions are included (`FINALIZED_AND_DRAFT`, the - default) or excluded (`FINALIZED`) from the balance calculation - - **Account hierarchies**: When querying a child customer, shared commits from - parent contracts are not included — query the parent customer directly to see - shared commit balances - - **Negative balances**: Manual ledger entries can cause negative segment - balances; these are treated as zero when calculating the net balance - - **Credit types**: If `credit_type_id` is not specified, the balance defaults - to USD (cents) - - Args: - customer_id: The ID of the customer. - - credit_type_id: The ID of the credit type (can be fiat or a custom pricing unit) to get the - balance for. Defaults to USD (cents) if not specified. - - filters: Balance filters are OR'd together, so if a given commit or credit matches any of - the filters, it will be included in the net balance. - - invoice_inclusion_mode: Controls which invoices are considered when calculating the remaining balance. - `FINALIZED` considers only deductions from finalized invoices. - `FINALIZED_AND_DRAFT` also includes deductions from pending draft invoices. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contracts/customerBalances/getNetBalance", - body=maybe_transform( - { - "customer_id": customer_id, - "credit_type_id": credit_type_id, - "filters": filters, - "invoice_inclusion_mode": invoice_inclusion_mode, - }, - contract_get_net_balance_params.ContractGetNetBalanceParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractGetNetBalanceResponse, - ) - - def list_balances( - self, - *, - customer_id: str, - id: str | Omit = omit, - covering_date: Union[str, datetime] | Omit = omit, - effective_before: Union[str, datetime] | Omit = omit, - exclude_zero_balances: bool | Omit = omit, - include_archived: bool | Omit = omit, - include_balance: bool | Omit = omit, - include_contract_balances: bool | Omit = omit, - include_ledgers: bool | Omit = omit, - limit: int | Omit = omit, - next_page: str | Omit = omit, - starting_at: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncBodyCursorPage[ContractListBalancesResponse]: - """ - Retrieve a comprehensive view of all available balances (commits and credits) - for a customer. This endpoint provides real-time visibility into prepaid funds, - postpaid commitments, promotional credits, and other balance types that can - offset usage charges, helping you build transparent billing experiences. - - ### Use this endpoint to: - - - Display current available balances in customer dashboards - - Verify available funds before approving high-usage operations - - Generate balance reports for finance teams - - Filter balances by contract or date ranges - - ### Key response fields: - - An array of balance objects (all credits and commits) containing: - - - Balance details: Current available amount for each commit or credit - - Metadata: Product associations, priorities, applicable date ranges - - Optional ledger entries: Detailed transaction history (if - `include_ledgers=true`) - - Balance calculations: Including pending transactions and future-dated entries - - Custom fields: Any additional metadata attached to balances - - ### Usage guidelines: - - - Date filtering: Use `effective_before` to include only balances with access - before a specific date (exclusive) - - Set `include_balance=true` for calculated balance amounts on each commit or - credit - - Set `include_ledgers=true` for full transaction history - - Set `include_contract_balances = true` to see contract level balances - - Balance logic: Reflects currently accessible amounts, excluding expired/future - segments - - Manual adjustments: Includes all manual ledger entries, even future-dated ones - - Args: - covering_date: Return only balances that have access schedules that "cover" the provided date - - effective_before: Include only balances that have any access before the provided date (exclusive) - - exclude_zero_balances: Exclude balances with zero amounts from the response. - - include_archived: Include archived credits and credits from archived contracts. - - include_balance: Include the balance of credits and commits in the response. Setting this flag - may cause the query to be slower. - - include_contract_balances: Include balances on the contract level. - - include_ledgers: Include ledgers in the response. Setting this flag may cause the query to be - slower. - - limit: The maximum number of commits to return. Defaults to 25. - - next_page: The next page token from a previous response. - - starting_at: Include only balances that have any access on or after the provided date - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/contracts/customerBalances/list", - page=SyncBodyCursorPage[ContractListBalancesResponse], - body=maybe_transform( - { - "customer_id": customer_id, - "id": id, - "covering_date": covering_date, - "effective_before": effective_before, - "exclude_zero_balances": exclude_zero_balances, - "include_archived": include_archived, - "include_balance": include_balance, - "include_contract_balances": include_contract_balances, - "include_ledgers": include_ledgers, - "limit": limit, - "next_page": next_page, - "starting_at": starting_at, - }, - contract_list_balances_params.ContractListBalancesParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - model=cast( - Any, ContractListBalancesResponse - ), # Union types cannot be passed in as arguments in the type system - method="post", - ) - - def retrieve_rate_schedule( - self, - *, - contract_id: str, - customer_id: str, - limit: int | Omit = omit, - next_page: str | Omit = omit, - at: Union[str, datetime] | Omit = omit, - selectors: Iterable[contract_retrieve_rate_schedule_params.Selector] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractRetrieveRateScheduleResponse: - """ - For a specific customer and contract, get the rates at a specific point in time. - This endpoint takes the contract's rate card into consideration, including - scheduled changes. It also takes into account overrides on the contract. - - For example, if you want to show your customer a summary of the prices they are - paying, inclusive of any negotiated discounts or promotions, use this endpoint. - This endpoint only returns rates that are entitled. - - Args: - contract_id: ID of the contract to get the rate schedule for. - - customer_id: ID of the customer for whose contract to get the rate schedule for. - - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - at: optional timestamp which overlaps with the returned rate schedule segments. When - not specified, the current timestamp will be used. - - selectors: List of rate selectors, rates matching ANY of the selectors will be included in - the response. Passing no selectors will result in all rates being returned. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contracts/getContractRateSchedule", - body=maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - "at": at, - "selectors": selectors, - }, - contract_retrieve_rate_schedule_params.ContractRetrieveRateScheduleParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - contract_retrieve_rate_schedule_params.ContractRetrieveRateScheduleParams, - ), - ), - cast_to=ContractRetrieveRateScheduleResponse, - ) - - def retrieve_subscription_quantity_history( - self, - *, - contract_id: str, - customer_id: str, - subscription_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractRetrieveSubscriptionQuantityHistoryResponse: - """ - Get the history of subscription quantities and prices over time for a given - `subscription_id`. This endpoint can be used to power an in-product experience - where you show a customer their historical changes to seat count. Future changes - are not included in this endpoint - use the `getContract` endpoint to view the - future scheduled changes to a subscription's quantity. - - Subscriptions are used to model fixed recurring fees as well as seat-based - recurring fees. To model changes to the number of seats in Metronome, you can - increment or decrement the quantity on a subscription at any point in the past - or future. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contracts/getSubscriptionQuantityHistory", - body=maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - "subscription_id": subscription_id, - }, - contract_retrieve_subscription_quantity_history_params.ContractRetrieveSubscriptionQuantityHistoryParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractRetrieveSubscriptionQuantityHistoryResponse, - ) - - def schedule_pro_services_invoice( - self, - *, - contract_id: str, - customer_id: str, - issued_at: Union[str, datetime], - line_items: Iterable[contract_schedule_pro_services_invoice_params.LineItem], - netsuite_invoice_header_end: Union[str, datetime] | Omit = omit, - netsuite_invoice_header_start: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractScheduleProServicesInvoiceResponse: - """ - Create a new scheduled invoice for Professional Services terms on a contract. - This endpoint's availability is dependent on your client's configuration. - - Args: - issued_at: The date the invoice is issued - - line_items: Each line requires an amount or both unit_price and quantity. - - netsuite_invoice_header_end: The end date of the invoice header in Netsuite - - netsuite_invoice_header_start: The start date of the invoice header in Netsuite - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contracts/scheduleProServicesInvoice", - body=maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - "issued_at": issued_at, - "line_items": line_items, - "netsuite_invoice_header_end": netsuite_invoice_header_end, - "netsuite_invoice_header_start": netsuite_invoice_header_start, - }, - contract_schedule_pro_services_invoice_params.ContractScheduleProServicesInvoiceParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractScheduleProServicesInvoiceResponse, - ) - - def set_usage_filter( - self, - *, - contract_id: str, - customer_id: str, - group_key: str, - group_values: SequenceNotStr[str], - starting_at: Union[str, datetime], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - If a customer has multiple contracts with overlapping rates, the usage filter - routes usage to the appropriate contract based on a predefined group key. - - As an example, imagine you have a customer associated with two projects. Each - project is associated with its own contract. You can create a usage filter with - group key `project_id` on each contract, and route usage for `project_1` to the - first contract and `project_2` to the second contract. - - ### Use this endpoint to: - - - Support enterprise contracting scenarios where multiple contracts are - associated to the same customer with the same rates. - - Update the usage filter associated with the contract over time. - - ### Usage guidelines: - - To use usage filters, the `group_key` must be defined on the billable metrics - underlying the rate card on the contracts. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._post( - "/v1/contracts/setUsageFilter", - body=maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - "group_key": group_key, - "group_values": group_values, - "starting_at": starting_at, - }, - contract_set_usage_filter_params.ContractSetUsageFilterParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def update_end_date( - self, - *, - contract_id: str, - customer_id: str, - allow_ending_before_finalized_invoice: bool | Omit = omit, - ending_before: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractUpdateEndDateResponse: - """Update or add an end date to a contract. - - Ending a contract early will impact - draft usage statements, truncate any terms, and remove upcoming scheduled - invoices. Moving the date into the future will only extend the contract length. - Terms and scheduled invoices are not extended. In-advance subscriptions will not - be extended. Use this if a contract's end date has changed or if a perpetual - contract ends. - - Args: - contract_id: ID of the contract to update - - customer_id: ID of the customer whose contract is to be updated - - allow_ending_before_finalized_invoice: If true, allows setting the contract end date earlier than the end_timestamp of - existing finalized invoices. Finalized invoices will be unchanged; if you want - to incorporate the new end date, you can void and regenerate finalized usage - invoices. Defaults to true. - - ending_before: RFC 3339 timestamp indicating when the contract will end (exclusive). If not - provided, the contract will be updated to be open-ended. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contracts/updateEndDate", - body=maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - "allow_ending_before_finalized_invoice": allow_ending_before_finalized_invoice, - "ending_before": ending_before, - }, - contract_update_end_date_params.ContractUpdateEndDateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractUpdateEndDateResponse, - ) - - -class AsyncContractsResource(AsyncAPIResource): - @cached_property - def products(self) -> AsyncProductsResource: - """Products are the items that customers purchase.""" - return AsyncProductsResource(self._client) - - @cached_property - def rate_cards(self) -> AsyncRateCardsResource: - """Rate cards are used to define default pricing for products.""" - return AsyncRateCardsResource(self._client) - - @cached_property - def named_schedules(self) -> AsyncNamedSchedulesResource: - """Named schedules are used for storing custom data that can change over time. - - Named schedules are often used in custom pricing logic. - """ - return AsyncNamedSchedulesResource(self._client) - - @cached_property - def with_raw_response(self) -> AsyncContractsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncContractsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncContractsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncContractsResourceWithStreamingResponse(self) - - async def create( - self, - *, - customer_id: str, - starting_at: Union[str, datetime], - billing_provider_configuration: contract_create_params.BillingProviderConfiguration | Omit = omit, - commits: Iterable[contract_create_params.Commit] | Omit = omit, - credits: Iterable[contract_create_params.Credit] | Omit = omit, - custom_fields: Dict[str, str] | Omit = omit, - discounts: Iterable[contract_create_params.Discount] | Omit = omit, - ending_before: Union[str, datetime] | Omit = omit, - hierarchy_configuration: contract_create_params.HierarchyConfiguration | Omit = omit, - multiplier_override_prioritization: Literal["LOWEST_MULTIPLIER", "EXPLICIT"] | Omit = omit, - name: str | Omit = omit, - net_payment_terms_days: float | Omit = omit, - netsuite_sales_order_id: str | Omit = omit, - overrides: Iterable[contract_create_params.Override] | Omit = omit, - package_alias: str | Omit = omit, - package_id: str | Omit = omit, - prepaid_balance_threshold_configuration: PrepaidBalanceThresholdConfiguration | Omit = omit, - professional_services: Iterable[contract_create_params.ProfessionalService] | Omit = omit, - rate_card_alias: str | Omit = omit, - rate_card_id: str | Omit = omit, - recurring_commits: Iterable[contract_create_params.RecurringCommit] | Omit = omit, - recurring_credits: Iterable[contract_create_params.RecurringCredit] | Omit = omit, - reseller_royalties: Iterable[contract_create_params.ResellerRoyalty] | Omit = omit, - revenue_system_configuration: contract_create_params.RevenueSystemConfiguration | Omit = omit, - salesforce_opportunity_id: str | Omit = omit, - scheduled_charges: Iterable[contract_create_params.ScheduledCharge] | Omit = omit, - scheduled_charges_on_usage_invoices: Literal["ALL"] | Omit = omit, - spend_threshold_configuration: SpendThresholdConfiguration | Omit = omit, - subscriptions: Iterable[contract_create_params.Subscription] | Omit = omit, - total_contract_value: float | Omit = omit, - transition: contract_create_params.Transition | Omit = omit, - uniqueness_key: str | Omit = omit, - usage_filter: BaseUsageFilter | Omit = omit, - usage_statement_schedule: contract_create_params.UsageStatementSchedule | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractCreateResponse: - """ - Contracts define a customer's products, pricing, discounts, access duration, and - billing configuration. Contracts serve as the central billing agreement for both - PLG and Enterprise customers, you can automatically customers access to your - products and services directly from your product or CRM. - - ### Use this endpoint to: - - - PLG onboarding: Automatically provision new self-serve customers with - contracts when they sign up. - - Enterprise sales: Push negotiated contracts from Salesforce with custom - pricing and commitments - - Promotional pricing: Implement time-limited discounts and free trials through - overrides - - ### Key components: - - #### Contract Term and Billing Schedule - - - Set contract duration using `starting_at` and `ending_before` fields. PLG - contracts typically use perpetual agreements (no end date), while Enterprise - contracts have fixed end dates which can be edited over time in the case of - co-term upsells. - - #### Rate Card - - If you are offering usage based pricing, you can set a rate card for the - contract to reference through `rate_card_id` or `rate_card_alias`. The rate card - is a store of all of your usage based products and their centralized pricing. - Any new products or price changes on the rate card can be set to automatically - propagate to all associated contracts - this ensures consistent pricing and - product launches flow to contracts without manual updates and migrations. The - `usage_statement_schedule` determines the cadence on which Metronome will - finalize a usage invoice for the customer. This defaults to monthly on the 1st, - with options for custom dates, quarterly, or annual cadences. Note: Most usage - based billing companies align usage statements to be evaluated aligned to the - first of the month. Read more about - [Rate Cards](https://docs.metronome.com/pricing-packaging/create-manage-rate-cards/). - - #### Overrides and discounts - - Customize pricing on the contract through time-bounded overrides that can target - specific products, product families, or complex usage scenarios. Overrides - enable two key capabilities: - - - Discounts: Apply percentage discounts, fixed rate reductions, or - quantity-based pricing tiers - - Entitlements: Provide special pricing or access to specific products for - negotiated deals - - Read more about - [Contract Overrides](https://docs.metronome.com/manage-product-access/add-contract-override/). - - #### Commits and Credits - - Using commits, configure prepaid or postpaid spending commitments where - customers promise to spend a certain amount over the contract period paid in - advance or in arrears. Use credits to provide free spending allowances. Under - the hood these are the same mechanisms, however, credits are typically offered - for free (SLA or promotional) or as a part of an allotment associated with a - Subscription. - - In Metronome, you can set commits and credits to only be applicable for a subset - of usage. Use `applicable_product_ids` or `applicable_product_tags` to create - product or product-family specific commits or credits, or you can build complex - boolean logic specifiers to target usage based on pricing and presentation group - values using `override_specifiers`. - - These objects can also also be configured to have a recurrence schedule to - easily model customer packaging which includes recurring monthly or quarterly - allotments. - - Commits support rollover settings (`rollover_fraction`) to transfer unused - balances between contract periods, either entirely or as a percentage. - - Read more about - [Credits and Commits](https://docs.metronome.com/pricing-packaging/apply-credits-commits/). - - #### Subscriptions - - You can add a fixed recurring charge to a contract, like monthly licenses or - seat-based fees, using the subscription charge. Subscription charges are defined - on your rate card and you can select which subscription is applicable to add to - each contract. When you add a subscription to a contract you need to: - - - Define whether the subscription is paid for in-advance or in-arrears - (`collection_schedule`) - - Define the proration behavior (`proration`) - - Specify an initial quantity (`initial_quantity`) - - Define which subscription rate on the rate card should be used - (`subscription_rate`) - - Read more about - [Subscriptions](https://docs.metronome.com/manage-product-access/create-subscription/). - - #### Scheduled Charges - - Set up one-time, recurring, or entirely custom charges that occur on specific - dates, separate from usage-based billing or commitments. These can be used to - model non-recurring platform charges or professional services. - - #### Threshold Billing - - Metronome allows you to configure automatic billing triggers when customers - reach spending thresholds to prevent fraud and manage risk. You can use - `spend_threshold_configuration` to trigger an invoice to cover current charges - whenever the threshold is reached or you can ensure the customer maintains a - minimum prepaid balance using the `prepaid_balance_configuration`. - - Read more about - [Spend Threshold](https://docs.metronome.com/manage-product-access/spend-thresholds/) - and - [Prepaid Balance Thresholds](https://docs.metronome.com/manage-product-access/prepaid-balance-thresholds/). - - ### Usage guidelines: - - - You can always - [Edit Contracts](https://docs.metronome.com/manage-product-access/edit-contract/) - after it has been created, using the `editContract` endpoint. Metronome keeps - track of all edits, both in the audit log and over the `getEditHistory` - endpoint. - - Customers in Metronome can have multiple concurrent contracts at one time. Use - `usage_filters` to route the correct usage to each contract. - [Read more about usage filters](https://docs.metronome.com/manage-product-access/provision-customer/#create-a-usage-filter). - - Args: - starting_at: inclusive contract start time - - billing_provider_configuration: The billing provider configuration associated with a contract. Provide either an - ID or the provider and delivery method. - - custom_fields: Custom fields to be added eg. { "key1": "value1", "key2": "value2" } - - discounts: This field's availability is dependent on your client's configuration. - - ending_before: exclusive contract end time - - multiplier_override_prioritization: Defaults to LOWEST_MULTIPLIER, which applies the greatest discount to list - prices automatically. EXPLICIT prioritization requires specifying priorities for - each multiplier; the one with the lowest priority value will be prioritized - first. If tiered overrides are used, prioritization must be explicit. - - netsuite_sales_order_id: This field's availability is dependent on your client's configuration. - - package_alias: Selects the package linked to the specified alias as of the contract's start - date. Mutually exclusive with package_id. - - package_id: If provided, provisions a customer on a package instead of creating a - traditional contract. When specified, only customer_id, starting_at, package_id, - and uniqueness_key are allowed. - - professional_services: This field's availability is dependent on your client's configuration. - - rate_card_alias: Selects the rate card linked to the specified alias as of the contract's start - date. - - reseller_royalties: This field's availability is dependent on your client's configuration. - - revenue_system_configuration: The revenue system configuration associated with a contract. Provide either an - ID or the provider and delivery method. - - salesforce_opportunity_id: This field's availability is dependent on your client's configuration. - - scheduled_charges_on_usage_invoices: Determines which scheduled and commit charges to consolidate onto the Contract's - usage invoice. The charge's `timestamp` must match the usage invoice's - `ending_before` date for consolidation to occur. This field cannot be modified - after a Contract has been created. If this field is omitted, charges will appear - on a separate invoice from usage charges. - - subscriptions: Optional list of - [subscriptions](https://docs.metronome.com/manage-product-access/create-subscription/) - to add to the contract. - - total_contract_value: This field's availability is dependent on your client's configuration. - - uniqueness_key: Prevents the creation of duplicates. If a request to create a record is made - with a previously used uniqueness key, a new record will not be created and the - request will fail with a 409 error. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contracts/create", - body=await async_maybe_transform( - { - "customer_id": customer_id, - "starting_at": starting_at, - "billing_provider_configuration": billing_provider_configuration, - "commits": commits, - "credits": credits, - "custom_fields": custom_fields, - "discounts": discounts, - "ending_before": ending_before, - "hierarchy_configuration": hierarchy_configuration, - "multiplier_override_prioritization": multiplier_override_prioritization, - "name": name, - "net_payment_terms_days": net_payment_terms_days, - "netsuite_sales_order_id": netsuite_sales_order_id, - "overrides": overrides, - "package_alias": package_alias, - "package_id": package_id, - "prepaid_balance_threshold_configuration": prepaid_balance_threshold_configuration, - "professional_services": professional_services, - "rate_card_alias": rate_card_alias, - "rate_card_id": rate_card_id, - "recurring_commits": recurring_commits, - "recurring_credits": recurring_credits, - "reseller_royalties": reseller_royalties, - "revenue_system_configuration": revenue_system_configuration, - "salesforce_opportunity_id": salesforce_opportunity_id, - "scheduled_charges": scheduled_charges, - "scheduled_charges_on_usage_invoices": scheduled_charges_on_usage_invoices, - "spend_threshold_configuration": spend_threshold_configuration, - "subscriptions": subscriptions, - "total_contract_value": total_contract_value, - "transition": transition, - "uniqueness_key": uniqueness_key, - "usage_filter": usage_filter, - "usage_statement_schedule": usage_statement_schedule, - }, - contract_create_params.ContractCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractCreateResponse, - ) - - async def retrieve( - self, - *, - contract_id: str, - customer_id: str, - include_balance: bool | Omit = omit, - include_ledgers: bool | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractRetrieveResponse: - """This is the v1 endpoint to get a contract. - - New clients should implement using - the v2 endpoint. - - Args: - include_balance: Include the balance of credits and commits in the response. Setting this flag - may cause the query to be slower. - - include_ledgers: Include commit ledgers in the response. Setting this flag may cause the query to - be slower. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contracts/get", - body=await async_maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - "include_balance": include_balance, - "include_ledgers": include_ledgers, - }, - contract_retrieve_params.ContractRetrieveParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractRetrieveResponse, - ) - - async def list( - self, - *, - customer_id: str, - covering_date: Union[str, datetime] | Omit = omit, - include_archived: bool | Omit = omit, - include_balance: bool | Omit = omit, - include_ledgers: bool | Omit = omit, - starting_at: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractListResponse: - """ - Retrieves all contracts for a specific customer, including pricing, terms, - credits, and commitments. Use this to view a customer's contract history and - current agreements for billing management. Returns contract details with - optional ledgers and balance information. - - ⚠️ Note: This is the legacy v1 endpoint - new integrations should use the v2 - endpoint for enhanced features. - - Args: - covering_date: Optional RFC 3339 timestamp. If provided, the response will include only - contracts effective on the provided date. This cannot be provided if the - starting_at filter is provided. - - include_archived: Include archived contracts in the response - - include_balance: Include the balance of credits and commits in the response. Setting this flag - may cause the query to be slower. - - include_ledgers: Include commit ledgers in the response. Setting this flag may cause the query to - be slower. - - starting_at: Optional RFC 3339 timestamp. If provided, the response will include only - contracts where effective_at is on or after the provided date. This cannot be - provided if the covering_date filter is provided. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contracts/list", - body=await async_maybe_transform( - { - "customer_id": customer_id, - "covering_date": covering_date, - "include_archived": include_archived, - "include_balance": include_balance, - "include_ledgers": include_ledgers, - "starting_at": starting_at, - }, - contract_list_params.ContractListParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractListResponse, - ) - - async def add_manual_balance_entry( - self, - *, - id: str, - amount: float, - customer_id: str, - reason: str, - segment_id: str, - contract_id: str | Omit = omit, - per_group_amounts: Dict[str, float] | Omit = omit, - timestamp: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """Manually adjust the available balance on a commit or credit. - - This entry is - appended to the commit ledger as a new event. Optionally include a description - that provides the reasoning for the entry. - - ### Use this endpoint to: - - - Address incorrect usage burn-down caused by malformed usage or invalid config - - Decrease available balance to account for outages where usage may have not - been tracked or sent to Metronome - - Issue credits to customers in the form of increased balance on existing commit - or credit - - ### Usage guidelines: - - Manual ledger entries can be extremely useful for resolving discrepancies in - Metronome. However, most corrections to inaccurate billings can be modified - upstream of the commit, whether that is via contract editing, rate editing, or - other actions that cause an invoice to be recalculated. - - Args: - id: ID of the balance (commit or credit) to update. - - amount: Amount to add to the segment. A negative number will draw down from the balance. - - customer_id: ID of the customer whose balance is to be updated. - - reason: Reason for the manual adjustment. This will be displayed in the ledger. - - segment_id: ID of the segment to update. - - contract_id: ID of the contract to update. Leave blank to update a customer level balance. - - per_group_amounts: If using individually configured commits/credits attached to seat managed - subscriptions, the amount to add for each seat. Must sum to total amount. - - timestamp: RFC 3339 timestamp indicating when the manual adjustment takes place. If not - provided, it will default to the start of the segment. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._post( - "/v1/contracts/addManualBalanceLedgerEntry", - body=await async_maybe_transform( - { - "id": id, - "amount": amount, - "customer_id": customer_id, - "reason": reason, - "segment_id": segment_id, - "contract_id": contract_id, - "per_group_amounts": per_group_amounts, - "timestamp": timestamp, - }, - contract_add_manual_balance_entry_params.ContractAddManualBalanceEntryParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - async def amend( - self, - *, - contract_id: str, - customer_id: str, - starting_at: Union[str, datetime], - commits: Iterable[contract_amend_params.Commit] | Omit = omit, - credits: Iterable[contract_amend_params.Credit] | Omit = omit, - custom_fields: Dict[str, str] | Omit = omit, - discounts: Iterable[contract_amend_params.Discount] | Omit = omit, - netsuite_sales_order_id: str | Omit = omit, - overrides: Iterable[contract_amend_params.Override] | Omit = omit, - professional_services: Iterable[contract_amend_params.ProfessionalService] | Omit = omit, - reseller_royalties: Iterable[contract_amend_params.ResellerRoyalty] | Omit = omit, - salesforce_opportunity_id: str | Omit = omit, - scheduled_charges: Iterable[contract_amend_params.ScheduledCharge] | Omit = omit, - total_contract_value: float | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractAmendResponse: - """Amendments will be replaced by Contract editing. - - New clients should implement - using the `editContract` endpoint. Read more about the migration to contract - editing [here](/guides/implement-metronome/migrate-amendments-to-edits/) and - reach out to your Metronome representative for more details. Once contract - editing is enabled, access to this endpoint will be removed. - - Args: - contract_id: ID of the contract to amend - - customer_id: ID of the customer whose contract is to be amended - - starting_at: inclusive start time for the amendment - - custom_fields: Custom fields to be added eg. { "key1": "value1", "key2": "value2" } - - discounts: This field's availability is dependent on your client's configuration. - - netsuite_sales_order_id: This field's availability is dependent on your client's configuration. - - professional_services: This field's availability is dependent on your client's configuration. - - reseller_royalties: This field's availability is dependent on your client's configuration. - - salesforce_opportunity_id: This field's availability is dependent on your client's configuration. - - total_contract_value: This field's availability is dependent on your client's configuration. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contracts/amend", - body=await async_maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - "starting_at": starting_at, - "commits": commits, - "credits": credits, - "custom_fields": custom_fields, - "discounts": discounts, - "netsuite_sales_order_id": netsuite_sales_order_id, - "overrides": overrides, - "professional_services": professional_services, - "reseller_royalties": reseller_royalties, - "salesforce_opportunity_id": salesforce_opportunity_id, - "scheduled_charges": scheduled_charges, - "total_contract_value": total_contract_value, - }, - contract_amend_params.ContractAmendParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractAmendResponse, - ) - - async def archive( - self, - *, - contract_id: str, - customer_id: str, - void_invoices: bool, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractArchiveResponse: - """Permanently end and archive a contract along with all its terms. - - Any draft - invoices will be canceled, and all upcoming scheduled invoices will be - voided–also all finalized invoices can optionally be voided. Use this in the - event a contract was incorrectly created and needed to be removed from a - customer. - - #### Impact on commits and credits: - - When archiving a contract, all associated commits and credits are also archived. - For prepaid commits with active segments, Metronome automatically generates - expiration ledger entries to close out any remaining balances, ensuring accurate - accounting of unused prepaid amounts. These ledger entries will appear in the - commit's transaction history with type `PREPAID_COMMIT_EXPIRATION`. - - #### Archived contract visibility: - - Archived contracts remain accessible for historical reporting and audit - purposes. They can be retrieved using the `ListContracts` endpoint by setting - the `include_archived` parameter to `true` or in the Metronome UI when the "Show - archived" option is enabled. - - Args: - contract_id: ID of the contract to archive - - customer_id: ID of the customer whose contract is to be archived - - void_invoices: If false, the existing finalized invoices will remain after the contract is - archived. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contracts/archive", - body=await async_maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - "void_invoices": void_invoices, - }, - contract_archive_params.ContractArchiveParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractArchiveResponse, - ) - - async def create_historical_invoices( - self, - *, - invoices: Iterable[contract_create_historical_invoices_params.Invoice], - preview: bool, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractCreateHistoricalInvoicesResponse: - """ - Create historical usage invoices for past billing periods on specific contracts. - Use this endpoint to generate retroactive invoices with custom usage line items, - quantities, and date ranges. Supports preview mode to validate invoice data - before creation. Ideal for billing migrations or correcting past billing - periods. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contracts/createHistoricalInvoices", - body=await async_maybe_transform( - { - "invoices": invoices, - "preview": preview, - }, - contract_create_historical_invoices_params.ContractCreateHistoricalInvoicesParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractCreateHistoricalInvoicesResponse, - ) - - async def get_net_balance( - self, - *, - customer_id: str, - credit_type_id: str | Omit = omit, - filters: Iterable[BalanceFilter] | Omit = omit, - invoice_inclusion_mode: Literal["FINALIZED", "FINALIZED_AND_DRAFT"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractGetNetBalanceResponse: - """ - Retrieve the combined current balance across any grouping of credits and commits - for a customer in a single API call. - - - Display real-time available balance to customers in billing dashboards - - Build finance dashboards showing credit utilization across customer segments - - Validate expected vs. actual balance during billing reconciliation - - ### Key response fields: - - - `balance`: The combined net balance available to use at this moment across all - matching commits and credits - - `credit_type_id`: The credit type (fiat or custom pricing unit) the balance is - denominated in - - ### Filtering options: - - Balance filters allow you to scope the calculation to specific subsets of - commits and credits. When using multiple filter objects, they are OR'd together - — if a commit or credit matches any filter, it's included in the net balance. - Within a single filter object, all specified conditions are AND'd together. - - - **Balance types**: Include any combination of `PREPAID_COMMIT`, - `POSTPAID_COMMIT`, and `CREDIT` (e.g., `["PREPAID_COMMIT", "CREDIT"]` to - exclude postpaid commits). If not specified, all balance types are included. - - **Specific IDs**: Target exact commit or credit IDs for precise balance - queries - - **Custom fields**: Filter by custom field key-value pairs; when multiple pairs - are provided, commits must match all of them - - **Example**: To get the balance of all free-trial credits OR all - signup-promotion commits, you'd pass two filter objects — one filtering for - CREDIT with custom field campaign: free-trial, and another filtering for - PREPAID_COMMIT with custom field campaign: signup-promotion. - - ### Usage guidelines: - - - **Draft invoice handling**: Use `invoice_inclusion_mode` to control whether - pending draft invoice deductions are included (`FINALIZED_AND_DRAFT`, the - default) or excluded (`FINALIZED`) from the balance calculation - - **Account hierarchies**: When querying a child customer, shared commits from - parent contracts are not included — query the parent customer directly to see - shared commit balances - - **Negative balances**: Manual ledger entries can cause negative segment - balances; these are treated as zero when calculating the net balance - - **Credit types**: If `credit_type_id` is not specified, the balance defaults - to USD (cents) - - Args: - customer_id: The ID of the customer. - - credit_type_id: The ID of the credit type (can be fiat or a custom pricing unit) to get the - balance for. Defaults to USD (cents) if not specified. - - filters: Balance filters are OR'd together, so if a given commit or credit matches any of - the filters, it will be included in the net balance. - - invoice_inclusion_mode: Controls which invoices are considered when calculating the remaining balance. - `FINALIZED` considers only deductions from finalized invoices. - `FINALIZED_AND_DRAFT` also includes deductions from pending draft invoices. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contracts/customerBalances/getNetBalance", - body=await async_maybe_transform( - { - "customer_id": customer_id, - "credit_type_id": credit_type_id, - "filters": filters, - "invoice_inclusion_mode": invoice_inclusion_mode, - }, - contract_get_net_balance_params.ContractGetNetBalanceParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractGetNetBalanceResponse, - ) - - def list_balances( - self, - *, - customer_id: str, - id: str | Omit = omit, - covering_date: Union[str, datetime] | Omit = omit, - effective_before: Union[str, datetime] | Omit = omit, - exclude_zero_balances: bool | Omit = omit, - include_archived: bool | Omit = omit, - include_balance: bool | Omit = omit, - include_contract_balances: bool | Omit = omit, - include_ledgers: bool | Omit = omit, - limit: int | Omit = omit, - next_page: str | Omit = omit, - starting_at: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[ContractListBalancesResponse, AsyncBodyCursorPage[ContractListBalancesResponse]]: - """ - Retrieve a comprehensive view of all available balances (commits and credits) - for a customer. This endpoint provides real-time visibility into prepaid funds, - postpaid commitments, promotional credits, and other balance types that can - offset usage charges, helping you build transparent billing experiences. - - ### Use this endpoint to: - - - Display current available balances in customer dashboards - - Verify available funds before approving high-usage operations - - Generate balance reports for finance teams - - Filter balances by contract or date ranges - - ### Key response fields: - - An array of balance objects (all credits and commits) containing: - - - Balance details: Current available amount for each commit or credit - - Metadata: Product associations, priorities, applicable date ranges - - Optional ledger entries: Detailed transaction history (if - `include_ledgers=true`) - - Balance calculations: Including pending transactions and future-dated entries - - Custom fields: Any additional metadata attached to balances - - ### Usage guidelines: - - - Date filtering: Use `effective_before` to include only balances with access - before a specific date (exclusive) - - Set `include_balance=true` for calculated balance amounts on each commit or - credit - - Set `include_ledgers=true` for full transaction history - - Set `include_contract_balances = true` to see contract level balances - - Balance logic: Reflects currently accessible amounts, excluding expired/future - segments - - Manual adjustments: Includes all manual ledger entries, even future-dated ones - - Args: - covering_date: Return only balances that have access schedules that "cover" the provided date - - effective_before: Include only balances that have any access before the provided date (exclusive) - - exclude_zero_balances: Exclude balances with zero amounts from the response. - - include_archived: Include archived credits and credits from archived contracts. - - include_balance: Include the balance of credits and commits in the response. Setting this flag - may cause the query to be slower. - - include_contract_balances: Include balances on the contract level. - - include_ledgers: Include ledgers in the response. Setting this flag may cause the query to be - slower. - - limit: The maximum number of commits to return. Defaults to 25. - - next_page: The next page token from a previous response. - - starting_at: Include only balances that have any access on or after the provided date - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/contracts/customerBalances/list", - page=AsyncBodyCursorPage[ContractListBalancesResponse], - body=maybe_transform( - { - "customer_id": customer_id, - "id": id, - "covering_date": covering_date, - "effective_before": effective_before, - "exclude_zero_balances": exclude_zero_balances, - "include_archived": include_archived, - "include_balance": include_balance, - "include_contract_balances": include_contract_balances, - "include_ledgers": include_ledgers, - "limit": limit, - "next_page": next_page, - "starting_at": starting_at, - }, - contract_list_balances_params.ContractListBalancesParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - model=cast( - Any, ContractListBalancesResponse - ), # Union types cannot be passed in as arguments in the type system - method="post", - ) - - async def retrieve_rate_schedule( - self, - *, - contract_id: str, - customer_id: str, - limit: int | Omit = omit, - next_page: str | Omit = omit, - at: Union[str, datetime] | Omit = omit, - selectors: Iterable[contract_retrieve_rate_schedule_params.Selector] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractRetrieveRateScheduleResponse: - """ - For a specific customer and contract, get the rates at a specific point in time. - This endpoint takes the contract's rate card into consideration, including - scheduled changes. It also takes into account overrides on the contract. - - For example, if you want to show your customer a summary of the prices they are - paying, inclusive of any negotiated discounts or promotions, use this endpoint. - This endpoint only returns rates that are entitled. - - Args: - contract_id: ID of the contract to get the rate schedule for. - - customer_id: ID of the customer for whose contract to get the rate schedule for. - - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - at: optional timestamp which overlaps with the returned rate schedule segments. When - not specified, the current timestamp will be used. - - selectors: List of rate selectors, rates matching ANY of the selectors will be included in - the response. Passing no selectors will result in all rates being returned. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contracts/getContractRateSchedule", - body=await async_maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - "at": at, - "selectors": selectors, - }, - contract_retrieve_rate_schedule_params.ContractRetrieveRateScheduleParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - contract_retrieve_rate_schedule_params.ContractRetrieveRateScheduleParams, - ), - ), - cast_to=ContractRetrieveRateScheduleResponse, - ) - - async def retrieve_subscription_quantity_history( - self, - *, - contract_id: str, - customer_id: str, - subscription_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractRetrieveSubscriptionQuantityHistoryResponse: - """ - Get the history of subscription quantities and prices over time for a given - `subscription_id`. This endpoint can be used to power an in-product experience - where you show a customer their historical changes to seat count. Future changes - are not included in this endpoint - use the `getContract` endpoint to view the - future scheduled changes to a subscription's quantity. - - Subscriptions are used to model fixed recurring fees as well as seat-based - recurring fees. To model changes to the number of seats in Metronome, you can - increment or decrement the quantity on a subscription at any point in the past - or future. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contracts/getSubscriptionQuantityHistory", - body=await async_maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - "subscription_id": subscription_id, - }, - contract_retrieve_subscription_quantity_history_params.ContractRetrieveSubscriptionQuantityHistoryParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractRetrieveSubscriptionQuantityHistoryResponse, - ) - - async def schedule_pro_services_invoice( - self, - *, - contract_id: str, - customer_id: str, - issued_at: Union[str, datetime], - line_items: Iterable[contract_schedule_pro_services_invoice_params.LineItem], - netsuite_invoice_header_end: Union[str, datetime] | Omit = omit, - netsuite_invoice_header_start: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractScheduleProServicesInvoiceResponse: - """ - Create a new scheduled invoice for Professional Services terms on a contract. - This endpoint's availability is dependent on your client's configuration. - - Args: - issued_at: The date the invoice is issued - - line_items: Each line requires an amount or both unit_price and quantity. - - netsuite_invoice_header_end: The end date of the invoice header in Netsuite - - netsuite_invoice_header_start: The start date of the invoice header in Netsuite - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contracts/scheduleProServicesInvoice", - body=await async_maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - "issued_at": issued_at, - "line_items": line_items, - "netsuite_invoice_header_end": netsuite_invoice_header_end, - "netsuite_invoice_header_start": netsuite_invoice_header_start, - }, - contract_schedule_pro_services_invoice_params.ContractScheduleProServicesInvoiceParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractScheduleProServicesInvoiceResponse, - ) - - async def set_usage_filter( - self, - *, - contract_id: str, - customer_id: str, - group_key: str, - group_values: SequenceNotStr[str], - starting_at: Union[str, datetime], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - If a customer has multiple contracts with overlapping rates, the usage filter - routes usage to the appropriate contract based on a predefined group key. - - As an example, imagine you have a customer associated with two projects. Each - project is associated with its own contract. You can create a usage filter with - group key `project_id` on each contract, and route usage for `project_1` to the - first contract and `project_2` to the second contract. - - ### Use this endpoint to: - - - Support enterprise contracting scenarios where multiple contracts are - associated to the same customer with the same rates. - - Update the usage filter associated with the contract over time. - - ### Usage guidelines: - - To use usage filters, the `group_key` must be defined on the billable metrics - underlying the rate card on the contracts. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._post( - "/v1/contracts/setUsageFilter", - body=await async_maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - "group_key": group_key, - "group_values": group_values, - "starting_at": starting_at, - }, - contract_set_usage_filter_params.ContractSetUsageFilterParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - async def update_end_date( - self, - *, - contract_id: str, - customer_id: str, - allow_ending_before_finalized_invoice: bool | Omit = omit, - ending_before: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractUpdateEndDateResponse: - """Update or add an end date to a contract. - - Ending a contract early will impact - draft usage statements, truncate any terms, and remove upcoming scheduled - invoices. Moving the date into the future will only extend the contract length. - Terms and scheduled invoices are not extended. In-advance subscriptions will not - be extended. Use this if a contract's end date has changed or if a perpetual - contract ends. - - Args: - contract_id: ID of the contract to update - - customer_id: ID of the customer whose contract is to be updated - - allow_ending_before_finalized_invoice: If true, allows setting the contract end date earlier than the end_timestamp of - existing finalized invoices. Finalized invoices will be unchanged; if you want - to incorporate the new end date, you can void and regenerate finalized usage - invoices. Defaults to true. - - ending_before: RFC 3339 timestamp indicating when the contract will end (exclusive). If not - provided, the contract will be updated to be open-ended. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contracts/updateEndDate", - body=await async_maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - "allow_ending_before_finalized_invoice": allow_ending_before_finalized_invoice, - "ending_before": ending_before, - }, - contract_update_end_date_params.ContractUpdateEndDateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractUpdateEndDateResponse, - ) - - -class ContractsResourceWithRawResponse: - def __init__(self, contracts: ContractsResource) -> None: - self._contracts = contracts - - self.create = to_raw_response_wrapper( - contracts.create, - ) - self.retrieve = to_raw_response_wrapper( - contracts.retrieve, - ) - self.list = to_raw_response_wrapper( - contracts.list, - ) - self.add_manual_balance_entry = to_raw_response_wrapper( - contracts.add_manual_balance_entry, - ) - self.amend = to_raw_response_wrapper( - contracts.amend, - ) - self.archive = to_raw_response_wrapper( - contracts.archive, - ) - self.create_historical_invoices = to_raw_response_wrapper( - contracts.create_historical_invoices, - ) - self.get_net_balance = to_raw_response_wrapper( - contracts.get_net_balance, - ) - self.list_balances = to_raw_response_wrapper( - contracts.list_balances, - ) - self.retrieve_rate_schedule = to_raw_response_wrapper( - contracts.retrieve_rate_schedule, - ) - self.retrieve_subscription_quantity_history = to_raw_response_wrapper( - contracts.retrieve_subscription_quantity_history, - ) - self.schedule_pro_services_invoice = to_raw_response_wrapper( - contracts.schedule_pro_services_invoice, - ) - self.set_usage_filter = to_raw_response_wrapper( - contracts.set_usage_filter, - ) - self.update_end_date = to_raw_response_wrapper( - contracts.update_end_date, - ) - - @cached_property - def products(self) -> ProductsResourceWithRawResponse: - """Products are the items that customers purchase.""" - return ProductsResourceWithRawResponse(self._contracts.products) - - @cached_property - def rate_cards(self) -> RateCardsResourceWithRawResponse: - """Rate cards are used to define default pricing for products.""" - return RateCardsResourceWithRawResponse(self._contracts.rate_cards) - - @cached_property - def named_schedules(self) -> NamedSchedulesResourceWithRawResponse: - """Named schedules are used for storing custom data that can change over time. - - Named schedules are often used in custom pricing logic. - """ - return NamedSchedulesResourceWithRawResponse(self._contracts.named_schedules) - - -class AsyncContractsResourceWithRawResponse: - def __init__(self, contracts: AsyncContractsResource) -> None: - self._contracts = contracts - - self.create = async_to_raw_response_wrapper( - contracts.create, - ) - self.retrieve = async_to_raw_response_wrapper( - contracts.retrieve, - ) - self.list = async_to_raw_response_wrapper( - contracts.list, - ) - self.add_manual_balance_entry = async_to_raw_response_wrapper( - contracts.add_manual_balance_entry, - ) - self.amend = async_to_raw_response_wrapper( - contracts.amend, - ) - self.archive = async_to_raw_response_wrapper( - contracts.archive, - ) - self.create_historical_invoices = async_to_raw_response_wrapper( - contracts.create_historical_invoices, - ) - self.get_net_balance = async_to_raw_response_wrapper( - contracts.get_net_balance, - ) - self.list_balances = async_to_raw_response_wrapper( - contracts.list_balances, - ) - self.retrieve_rate_schedule = async_to_raw_response_wrapper( - contracts.retrieve_rate_schedule, - ) - self.retrieve_subscription_quantity_history = async_to_raw_response_wrapper( - contracts.retrieve_subscription_quantity_history, - ) - self.schedule_pro_services_invoice = async_to_raw_response_wrapper( - contracts.schedule_pro_services_invoice, - ) - self.set_usage_filter = async_to_raw_response_wrapper( - contracts.set_usage_filter, - ) - self.update_end_date = async_to_raw_response_wrapper( - contracts.update_end_date, - ) - - @cached_property - def products(self) -> AsyncProductsResourceWithRawResponse: - """Products are the items that customers purchase.""" - return AsyncProductsResourceWithRawResponse(self._contracts.products) - - @cached_property - def rate_cards(self) -> AsyncRateCardsResourceWithRawResponse: - """Rate cards are used to define default pricing for products.""" - return AsyncRateCardsResourceWithRawResponse(self._contracts.rate_cards) - - @cached_property - def named_schedules(self) -> AsyncNamedSchedulesResourceWithRawResponse: - """Named schedules are used for storing custom data that can change over time. - - Named schedules are often used in custom pricing logic. - """ - return AsyncNamedSchedulesResourceWithRawResponse(self._contracts.named_schedules) - - -class ContractsResourceWithStreamingResponse: - def __init__(self, contracts: ContractsResource) -> None: - self._contracts = contracts - - self.create = to_streamed_response_wrapper( - contracts.create, - ) - self.retrieve = to_streamed_response_wrapper( - contracts.retrieve, - ) - self.list = to_streamed_response_wrapper( - contracts.list, - ) - self.add_manual_balance_entry = to_streamed_response_wrapper( - contracts.add_manual_balance_entry, - ) - self.amend = to_streamed_response_wrapper( - contracts.amend, - ) - self.archive = to_streamed_response_wrapper( - contracts.archive, - ) - self.create_historical_invoices = to_streamed_response_wrapper( - contracts.create_historical_invoices, - ) - self.get_net_balance = to_streamed_response_wrapper( - contracts.get_net_balance, - ) - self.list_balances = to_streamed_response_wrapper( - contracts.list_balances, - ) - self.retrieve_rate_schedule = to_streamed_response_wrapper( - contracts.retrieve_rate_schedule, - ) - self.retrieve_subscription_quantity_history = to_streamed_response_wrapper( - contracts.retrieve_subscription_quantity_history, - ) - self.schedule_pro_services_invoice = to_streamed_response_wrapper( - contracts.schedule_pro_services_invoice, - ) - self.set_usage_filter = to_streamed_response_wrapper( - contracts.set_usage_filter, - ) - self.update_end_date = to_streamed_response_wrapper( - contracts.update_end_date, - ) - - @cached_property - def products(self) -> ProductsResourceWithStreamingResponse: - """Products are the items that customers purchase.""" - return ProductsResourceWithStreamingResponse(self._contracts.products) - - @cached_property - def rate_cards(self) -> RateCardsResourceWithStreamingResponse: - """Rate cards are used to define default pricing for products.""" - return RateCardsResourceWithStreamingResponse(self._contracts.rate_cards) - - @cached_property - def named_schedules(self) -> NamedSchedulesResourceWithStreamingResponse: - """Named schedules are used for storing custom data that can change over time. - - Named schedules are often used in custom pricing logic. - """ - return NamedSchedulesResourceWithStreamingResponse(self._contracts.named_schedules) - - -class AsyncContractsResourceWithStreamingResponse: - def __init__(self, contracts: AsyncContractsResource) -> None: - self._contracts = contracts - - self.create = async_to_streamed_response_wrapper( - contracts.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - contracts.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - contracts.list, - ) - self.add_manual_balance_entry = async_to_streamed_response_wrapper( - contracts.add_manual_balance_entry, - ) - self.amend = async_to_streamed_response_wrapper( - contracts.amend, - ) - self.archive = async_to_streamed_response_wrapper( - contracts.archive, - ) - self.create_historical_invoices = async_to_streamed_response_wrapper( - contracts.create_historical_invoices, - ) - self.get_net_balance = async_to_streamed_response_wrapper( - contracts.get_net_balance, - ) - self.list_balances = async_to_streamed_response_wrapper( - contracts.list_balances, - ) - self.retrieve_rate_schedule = async_to_streamed_response_wrapper( - contracts.retrieve_rate_schedule, - ) - self.retrieve_subscription_quantity_history = async_to_streamed_response_wrapper( - contracts.retrieve_subscription_quantity_history, - ) - self.schedule_pro_services_invoice = async_to_streamed_response_wrapper( - contracts.schedule_pro_services_invoice, - ) - self.set_usage_filter = async_to_streamed_response_wrapper( - contracts.set_usage_filter, - ) - self.update_end_date = async_to_streamed_response_wrapper( - contracts.update_end_date, - ) - - @cached_property - def products(self) -> AsyncProductsResourceWithStreamingResponse: - """Products are the items that customers purchase.""" - return AsyncProductsResourceWithStreamingResponse(self._contracts.products) - - @cached_property - def rate_cards(self) -> AsyncRateCardsResourceWithStreamingResponse: - """Rate cards are used to define default pricing for products.""" - return AsyncRateCardsResourceWithStreamingResponse(self._contracts.rate_cards) - - @cached_property - def named_schedules(self) -> AsyncNamedSchedulesResourceWithStreamingResponse: - """Named schedules are used for storing custom data that can change over time. - - Named schedules are often used in custom pricing logic. - """ - return AsyncNamedSchedulesResourceWithStreamingResponse(self._contracts.named_schedules) diff --git a/src/metronome/resources/v1/contracts/named_schedules.py b/src/metronome/resources/v1/contracts/named_schedules.py deleted file mode 100644 index d97c77575..000000000 --- a/src/metronome/resources/v1/contracts/named_schedules.py +++ /dev/null @@ -1,334 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime - -import httpx - -from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ...._base_client import make_request_options -from ....types.v1.contracts import named_schedule_update_params, named_schedule_retrieve_params -from ....types.v1.contracts.named_schedule_retrieve_response import NamedScheduleRetrieveResponse - -__all__ = ["NamedSchedulesResource", "AsyncNamedSchedulesResource"] - - -class NamedSchedulesResource(SyncAPIResource): - """Named schedules are used for storing custom data that can change over time. - - Named schedules are often used in custom pricing logic. - """ - - @cached_property - def with_raw_response(self) -> NamedSchedulesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return NamedSchedulesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> NamedSchedulesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return NamedSchedulesResourceWithStreamingResponse(self) - - def retrieve( - self, - *, - rate_card_id: str, - schedule_name: str, - covering_date: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> NamedScheduleRetrieveResponse: - """Get a named schedule for the given rate card. - - This endpoint's availability is - dependent on your client's configuration. - - Args: - rate_card_id: ID of the rate card whose named schedule is to be retrieved - - schedule_name: The identifier for the schedule to be retrieved - - covering_date: If provided, at most one schedule segment will be returned (the one that covers - this date). If not provided, all segments will be returned. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contract-pricing/rate-cards/getNamedSchedule", - body=maybe_transform( - { - "rate_card_id": rate_card_id, - "schedule_name": schedule_name, - "covering_date": covering_date, - }, - named_schedule_retrieve_params.NamedScheduleRetrieveParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NamedScheduleRetrieveResponse, - ) - - def update( - self, - *, - rate_card_id: str, - schedule_name: str, - starting_at: Union[str, datetime], - value: object, - ending_before: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """Update a named schedule for the given rate card. - - This endpoint's availability is - dependent on your client's configuration. - - Args: - rate_card_id: ID of the rate card whose named schedule is to be updated - - schedule_name: The identifier for the schedule to be updated - - value: The value to set for the named schedule. The structure of this object is - specific to the named schedule. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._post( - "/v1/contract-pricing/rate-cards/updateNamedSchedule", - body=maybe_transform( - { - "rate_card_id": rate_card_id, - "schedule_name": schedule_name, - "starting_at": starting_at, - "value": value, - "ending_before": ending_before, - }, - named_schedule_update_params.NamedScheduleUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class AsyncNamedSchedulesResource(AsyncAPIResource): - """Named schedules are used for storing custom data that can change over time. - - Named schedules are often used in custom pricing logic. - """ - - @cached_property - def with_raw_response(self) -> AsyncNamedSchedulesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncNamedSchedulesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncNamedSchedulesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncNamedSchedulesResourceWithStreamingResponse(self) - - async def retrieve( - self, - *, - rate_card_id: str, - schedule_name: str, - covering_date: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> NamedScheduleRetrieveResponse: - """Get a named schedule for the given rate card. - - This endpoint's availability is - dependent on your client's configuration. - - Args: - rate_card_id: ID of the rate card whose named schedule is to be retrieved - - schedule_name: The identifier for the schedule to be retrieved - - covering_date: If provided, at most one schedule segment will be returned (the one that covers - this date). If not provided, all segments will be returned. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contract-pricing/rate-cards/getNamedSchedule", - body=await async_maybe_transform( - { - "rate_card_id": rate_card_id, - "schedule_name": schedule_name, - "covering_date": covering_date, - }, - named_schedule_retrieve_params.NamedScheduleRetrieveParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NamedScheduleRetrieveResponse, - ) - - async def update( - self, - *, - rate_card_id: str, - schedule_name: str, - starting_at: Union[str, datetime], - value: object, - ending_before: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """Update a named schedule for the given rate card. - - This endpoint's availability is - dependent on your client's configuration. - - Args: - rate_card_id: ID of the rate card whose named schedule is to be updated - - schedule_name: The identifier for the schedule to be updated - - value: The value to set for the named schedule. The structure of this object is - specific to the named schedule. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._post( - "/v1/contract-pricing/rate-cards/updateNamedSchedule", - body=await async_maybe_transform( - { - "rate_card_id": rate_card_id, - "schedule_name": schedule_name, - "starting_at": starting_at, - "value": value, - "ending_before": ending_before, - }, - named_schedule_update_params.NamedScheduleUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class NamedSchedulesResourceWithRawResponse: - def __init__(self, named_schedules: NamedSchedulesResource) -> None: - self._named_schedules = named_schedules - - self.retrieve = to_raw_response_wrapper( - named_schedules.retrieve, - ) - self.update = to_raw_response_wrapper( - named_schedules.update, - ) - - -class AsyncNamedSchedulesResourceWithRawResponse: - def __init__(self, named_schedules: AsyncNamedSchedulesResource) -> None: - self._named_schedules = named_schedules - - self.retrieve = async_to_raw_response_wrapper( - named_schedules.retrieve, - ) - self.update = async_to_raw_response_wrapper( - named_schedules.update, - ) - - -class NamedSchedulesResourceWithStreamingResponse: - def __init__(self, named_schedules: NamedSchedulesResource) -> None: - self._named_schedules = named_schedules - - self.retrieve = to_streamed_response_wrapper( - named_schedules.retrieve, - ) - self.update = to_streamed_response_wrapper( - named_schedules.update, - ) - - -class AsyncNamedSchedulesResourceWithStreamingResponse: - def __init__(self, named_schedules: AsyncNamedSchedulesResource) -> None: - self._named_schedules = named_schedules - - self.retrieve = async_to_streamed_response_wrapper( - named_schedules.retrieve, - ) - self.update = async_to_streamed_response_wrapper( - named_schedules.update, - ) diff --git a/src/metronome/resources/v1/contracts/products.py b/src/metronome/resources/v1/contracts/products.py deleted file mode 100644 index e50c0a8fb..000000000 --- a/src/metronome/resources/v1/contracts/products.py +++ /dev/null @@ -1,896 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Optional -from datetime import datetime -from typing_extensions import Literal - -import httpx - -from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ....pagination import SyncCursorPage, AsyncCursorPage -from ...._base_client import AsyncPaginator, make_request_options -from ....types.v1.contracts import ( - product_list_params, - product_create_params, - product_update_params, - product_archive_params, - product_retrieve_params, -) -from ....types.v1.contracts.product_list_response import ProductListResponse -from ....types.v1.contracts.product_create_response import ProductCreateResponse -from ....types.v1.contracts.product_update_response import ProductUpdateResponse -from ....types.v1.contracts.quantity_rounding_param import QuantityRoundingParam -from ....types.v1.contracts.product_archive_response import ProductArchiveResponse -from ....types.v1.contracts.product_retrieve_response import ProductRetrieveResponse -from ....types.v1.contracts.quantity_conversion_param import QuantityConversionParam - -__all__ = ["ProductsResource", "AsyncProductsResource"] - - -class ProductsResource(SyncAPIResource): - """Products are the items that customers purchase.""" - - @cached_property - def with_raw_response(self) -> ProductsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return ProductsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ProductsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return ProductsResourceWithStreamingResponse(self) - - def create( - self, - *, - name: str, - type: Literal["FIXED", "USAGE", "COMPOSITE", "SUBSCRIPTION", "PROFESSIONAL_SERVICE", "PRO_SERVICE"], - billable_metric_id: str | Omit = omit, - composite_product_ids: SequenceNotStr[str] | Omit = omit, - composite_tags: SequenceNotStr[str] | Omit = omit, - custom_fields: Dict[str, str] | Omit = omit, - exclude_free_usage: bool | Omit = omit, - is_refundable: bool | Omit = omit, - netsuite_internal_item_id: str | Omit = omit, - netsuite_overage_item_id: str | Omit = omit, - presentation_group_key: SequenceNotStr[str] | Omit = omit, - pricing_group_key: SequenceNotStr[str] | Omit = omit, - quantity_conversion: Optional[QuantityConversionParam] | Omit = omit, - quantity_rounding: Optional[QuantityRoundingParam] | Omit = omit, - tags: SequenceNotStr[str] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ProductCreateResponse: - """Create a new product object. - - Products in Metronome represent your company's - individual product or service offerings. A Product can be thought of as the - basic unit of a line item on the invoice. This is analogous to SKUs or items in - an ERP system. Give the product a meaningful name as they will appear on - customer invoices. - - Args: - name: displayed on invoices - - billable_metric_id: Required for USAGE products - - composite_product_ids: Required for COMPOSITE products - - composite_tags: Required for COMPOSITE products - - custom_fields: Custom fields to be added eg. { "key1": "value1", "key2": "value2" } - - exclude_free_usage: Beta feature only available for composite products. If true, products with $0 - will not be included when computing composite usage. Defaults to false - - is_refundable: This field's availability is dependent on your client's configuration. Defaults - to true. - - netsuite_internal_item_id: This field's availability is dependent on your client's configuration. - - netsuite_overage_item_id: This field's availability is dependent on your client's configuration. - - presentation_group_key: For USAGE products only. Groups usage line items on invoices. The superset of - values in the pricing group key and presentation group key must be set as one - compound group key on the billable metric. - - pricing_group_key: For USAGE products only. If set, pricing for this product will be determined for - each pricing_group_key value, as opposed to the product as a whole. The superset - of values in the pricing group key and presentation group key must be set as one - compound group key on the billable metric. - - quantity_conversion: Optional. Only valid for USAGE products. If provided, the quantity will be - converted using the provided conversion factor and operation. For example, if - the operation is "multiply" and the conversion factor is 100, then the quantity - will be multiplied by 100. This can be used in cases where data is sent in one - unit and priced in another. For example, data could be sent in MB and priced in - GB. In this case, the conversion factor would be 1024 and the operation would be - "divide". - - quantity_rounding: Optional. Only valid for USAGE products. If provided, the quantity will be - rounded using the provided rounding method and decimal places. For example, if - the method is "round up" and the decimal places is 0, then the quantity will be - rounded up to the nearest integer. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contract-pricing/products/create", - body=maybe_transform( - { - "name": name, - "type": type, - "billable_metric_id": billable_metric_id, - "composite_product_ids": composite_product_ids, - "composite_tags": composite_tags, - "custom_fields": custom_fields, - "exclude_free_usage": exclude_free_usage, - "is_refundable": is_refundable, - "netsuite_internal_item_id": netsuite_internal_item_id, - "netsuite_overage_item_id": netsuite_overage_item_id, - "presentation_group_key": presentation_group_key, - "pricing_group_key": pricing_group_key, - "quantity_conversion": quantity_conversion, - "quantity_rounding": quantity_rounding, - "tags": tags, - }, - product_create_params.ProductCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ProductCreateResponse, - ) - - def retrieve( - self, - *, - id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ProductRetrieveResponse: - """ - Retrieve a product by its ID, including all metadata and historical changes. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contract-pricing/products/get", - body=maybe_transform({"id": id}, product_retrieve_params.ProductRetrieveParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ProductRetrieveResponse, - ) - - def update( - self, - *, - product_id: str, - starting_at: Union[str, datetime], - billable_metric_id: str | Omit = omit, - composite_product_ids: SequenceNotStr[str] | Omit = omit, - composite_tags: SequenceNotStr[str] | Omit = omit, - exclude_free_usage: bool | Omit = omit, - is_refundable: bool | Omit = omit, - name: str | Omit = omit, - netsuite_internal_item_id: str | Omit = omit, - netsuite_overage_item_id: str | Omit = omit, - presentation_group_key: SequenceNotStr[str] | Omit = omit, - pricing_group_key: SequenceNotStr[str] | Omit = omit, - quantity_conversion: Optional[QuantityConversionParam] | Omit = omit, - quantity_rounding: Optional[QuantityRoundingParam] | Omit = omit, - tags: SequenceNotStr[str] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ProductUpdateResponse: - """ - Updates a product's configuration while maintaining billing continuity for - active customers. Use this endpoint to modify product names, metrics, pricing - rules, and composite settings without disrupting ongoing billing cycles. Changes - are scheduled using the starting_at timestamp, which must be on an hour - boundary—set future dates to schedule updates ahead of time, or past dates for - retroactive changes. Returns the updated product ID upon success. - - ### Usage guidance: - - - Product type cannot be changed after creation. For incorrect product types, - create a new product and archive the original instead. - - Args: - product_id: ID of the product to update - - starting_at: Timestamp representing when the update should go into effect. It must be on an - hour boundary (e.g. 1:00, not 1:30). - - billable_metric_id: Available for USAGE products only. If not provided, defaults to product's - current billable metric. - - composite_product_ids: Available for COMPOSITE products only. If not provided, defaults to product's - current composite_product_ids. - - composite_tags: Available for COMPOSITE products only. If not provided, defaults to product's - current composite_tags. - - exclude_free_usage: Beta feature only available for composite products. If true, products with $0 - will not be included when computing composite usage. Defaults to false - - is_refundable: Defaults to product's current refundability status. This field's availability is - dependent on your client's configuration. - - name: displayed on invoices. If not provided, defaults to product's current name. - - netsuite_internal_item_id: If not provided, defaults to product's current netsuite_internal_item_id. This - field's availability is dependent on your client's configuration. - - netsuite_overage_item_id: Available for USAGE and COMPOSITE products only. If not provided, defaults to - product's current netsuite_overage_item_id. This field's availability is - dependent on your client's configuration. - - presentation_group_key: For USAGE products only. Groups usage line items on invoices. The superset of - values in the pricing group key and presentation group key must be set as one - compound group key on the billable metric. - - pricing_group_key: For USAGE products only. If set, pricing for this product will be determined for - each pricing_group_key value, as opposed to the product as a whole. The superset - of values in the pricing group key and presentation group key must be set as one - compound group key on the billable metric. - - quantity_conversion: Optional. Only valid for USAGE products. If provided, the quantity will be - converted using the provided conversion factor and operation. For example, if - the operation is "multiply" and the conversion factor is 100, then the quantity - will be multiplied by 100. This can be used in cases where data is sent in one - unit and priced in another. For example, data could be sent in MB and priced in - GB. In this case, the conversion factor would be 1024 and the operation would be - "divide". - - quantity_rounding: Optional. Only valid for USAGE products. If provided, the quantity will be - rounded using the provided rounding method and decimal places. For example, if - the method is "round up" and the decimal places is 0, then the quantity will be - rounded up to the nearest integer. - - tags: If not provided, defaults to product's current tags - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contract-pricing/products/update", - body=maybe_transform( - { - "product_id": product_id, - "starting_at": starting_at, - "billable_metric_id": billable_metric_id, - "composite_product_ids": composite_product_ids, - "composite_tags": composite_tags, - "exclude_free_usage": exclude_free_usage, - "is_refundable": is_refundable, - "name": name, - "netsuite_internal_item_id": netsuite_internal_item_id, - "netsuite_overage_item_id": netsuite_overage_item_id, - "presentation_group_key": presentation_group_key, - "pricing_group_key": pricing_group_key, - "quantity_conversion": quantity_conversion, - "quantity_rounding": quantity_rounding, - "tags": tags, - }, - product_update_params.ProductUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ProductUpdateResponse, - ) - - def list( - self, - *, - limit: int | Omit = omit, - next_page: str | Omit = omit, - archive_filter: Literal["ARCHIVED", "NOT_ARCHIVED", "ALL"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[ProductListResponse]: - """ - Get a paginated list of all products in your organization with their complete - configuration, version history, and metadata. By default excludes archived - products unless explicitly requested via the `archive_filter` parameter. - - Args: - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - archive_filter: Filter options for the product list. If not provided, defaults to not archived. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/contract-pricing/products/list", - page=SyncCursorPage[ProductListResponse], - body=maybe_transform({"archive_filter": archive_filter}, product_list_params.ProductListParams), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - product_list_params.ProductListParams, - ), - ), - model=ProductListResponse, - method="post", - ) - - def archive( - self, - *, - product_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ProductArchiveResponse: - """Archive a product. - - Any current rate cards associated with this product will - continue to function as normal. However, it will no longer be available as an - option for newly created rates. Once you archive a product, you can still - retrieve it in the UI and API, but you cannot unarchive it. - - Args: - product_id: ID of the product to be archived - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contract-pricing/products/archive", - body=maybe_transform({"product_id": product_id}, product_archive_params.ProductArchiveParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ProductArchiveResponse, - ) - - -class AsyncProductsResource(AsyncAPIResource): - """Products are the items that customers purchase.""" - - @cached_property - def with_raw_response(self) -> AsyncProductsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncProductsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncProductsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncProductsResourceWithStreamingResponse(self) - - async def create( - self, - *, - name: str, - type: Literal["FIXED", "USAGE", "COMPOSITE", "SUBSCRIPTION", "PROFESSIONAL_SERVICE", "PRO_SERVICE"], - billable_metric_id: str | Omit = omit, - composite_product_ids: SequenceNotStr[str] | Omit = omit, - composite_tags: SequenceNotStr[str] | Omit = omit, - custom_fields: Dict[str, str] | Omit = omit, - exclude_free_usage: bool | Omit = omit, - is_refundable: bool | Omit = omit, - netsuite_internal_item_id: str | Omit = omit, - netsuite_overage_item_id: str | Omit = omit, - presentation_group_key: SequenceNotStr[str] | Omit = omit, - pricing_group_key: SequenceNotStr[str] | Omit = omit, - quantity_conversion: Optional[QuantityConversionParam] | Omit = omit, - quantity_rounding: Optional[QuantityRoundingParam] | Omit = omit, - tags: SequenceNotStr[str] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ProductCreateResponse: - """Create a new product object. - - Products in Metronome represent your company's - individual product or service offerings. A Product can be thought of as the - basic unit of a line item on the invoice. This is analogous to SKUs or items in - an ERP system. Give the product a meaningful name as they will appear on - customer invoices. - - Args: - name: displayed on invoices - - billable_metric_id: Required for USAGE products - - composite_product_ids: Required for COMPOSITE products - - composite_tags: Required for COMPOSITE products - - custom_fields: Custom fields to be added eg. { "key1": "value1", "key2": "value2" } - - exclude_free_usage: Beta feature only available for composite products. If true, products with $0 - will not be included when computing composite usage. Defaults to false - - is_refundable: This field's availability is dependent on your client's configuration. Defaults - to true. - - netsuite_internal_item_id: This field's availability is dependent on your client's configuration. - - netsuite_overage_item_id: This field's availability is dependent on your client's configuration. - - presentation_group_key: For USAGE products only. Groups usage line items on invoices. The superset of - values in the pricing group key and presentation group key must be set as one - compound group key on the billable metric. - - pricing_group_key: For USAGE products only. If set, pricing for this product will be determined for - each pricing_group_key value, as opposed to the product as a whole. The superset - of values in the pricing group key and presentation group key must be set as one - compound group key on the billable metric. - - quantity_conversion: Optional. Only valid for USAGE products. If provided, the quantity will be - converted using the provided conversion factor and operation. For example, if - the operation is "multiply" and the conversion factor is 100, then the quantity - will be multiplied by 100. This can be used in cases where data is sent in one - unit and priced in another. For example, data could be sent in MB and priced in - GB. In this case, the conversion factor would be 1024 and the operation would be - "divide". - - quantity_rounding: Optional. Only valid for USAGE products. If provided, the quantity will be - rounded using the provided rounding method and decimal places. For example, if - the method is "round up" and the decimal places is 0, then the quantity will be - rounded up to the nearest integer. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contract-pricing/products/create", - body=await async_maybe_transform( - { - "name": name, - "type": type, - "billable_metric_id": billable_metric_id, - "composite_product_ids": composite_product_ids, - "composite_tags": composite_tags, - "custom_fields": custom_fields, - "exclude_free_usage": exclude_free_usage, - "is_refundable": is_refundable, - "netsuite_internal_item_id": netsuite_internal_item_id, - "netsuite_overage_item_id": netsuite_overage_item_id, - "presentation_group_key": presentation_group_key, - "pricing_group_key": pricing_group_key, - "quantity_conversion": quantity_conversion, - "quantity_rounding": quantity_rounding, - "tags": tags, - }, - product_create_params.ProductCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ProductCreateResponse, - ) - - async def retrieve( - self, - *, - id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ProductRetrieveResponse: - """ - Retrieve a product by its ID, including all metadata and historical changes. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contract-pricing/products/get", - body=await async_maybe_transform({"id": id}, product_retrieve_params.ProductRetrieveParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ProductRetrieveResponse, - ) - - async def update( - self, - *, - product_id: str, - starting_at: Union[str, datetime], - billable_metric_id: str | Omit = omit, - composite_product_ids: SequenceNotStr[str] | Omit = omit, - composite_tags: SequenceNotStr[str] | Omit = omit, - exclude_free_usage: bool | Omit = omit, - is_refundable: bool | Omit = omit, - name: str | Omit = omit, - netsuite_internal_item_id: str | Omit = omit, - netsuite_overage_item_id: str | Omit = omit, - presentation_group_key: SequenceNotStr[str] | Omit = omit, - pricing_group_key: SequenceNotStr[str] | Omit = omit, - quantity_conversion: Optional[QuantityConversionParam] | Omit = omit, - quantity_rounding: Optional[QuantityRoundingParam] | Omit = omit, - tags: SequenceNotStr[str] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ProductUpdateResponse: - """ - Updates a product's configuration while maintaining billing continuity for - active customers. Use this endpoint to modify product names, metrics, pricing - rules, and composite settings without disrupting ongoing billing cycles. Changes - are scheduled using the starting_at timestamp, which must be on an hour - boundary—set future dates to schedule updates ahead of time, or past dates for - retroactive changes. Returns the updated product ID upon success. - - ### Usage guidance: - - - Product type cannot be changed after creation. For incorrect product types, - create a new product and archive the original instead. - - Args: - product_id: ID of the product to update - - starting_at: Timestamp representing when the update should go into effect. It must be on an - hour boundary (e.g. 1:00, not 1:30). - - billable_metric_id: Available for USAGE products only. If not provided, defaults to product's - current billable metric. - - composite_product_ids: Available for COMPOSITE products only. If not provided, defaults to product's - current composite_product_ids. - - composite_tags: Available for COMPOSITE products only. If not provided, defaults to product's - current composite_tags. - - exclude_free_usage: Beta feature only available for composite products. If true, products with $0 - will not be included when computing composite usage. Defaults to false - - is_refundable: Defaults to product's current refundability status. This field's availability is - dependent on your client's configuration. - - name: displayed on invoices. If not provided, defaults to product's current name. - - netsuite_internal_item_id: If not provided, defaults to product's current netsuite_internal_item_id. This - field's availability is dependent on your client's configuration. - - netsuite_overage_item_id: Available for USAGE and COMPOSITE products only. If not provided, defaults to - product's current netsuite_overage_item_id. This field's availability is - dependent on your client's configuration. - - presentation_group_key: For USAGE products only. Groups usage line items on invoices. The superset of - values in the pricing group key and presentation group key must be set as one - compound group key on the billable metric. - - pricing_group_key: For USAGE products only. If set, pricing for this product will be determined for - each pricing_group_key value, as opposed to the product as a whole. The superset - of values in the pricing group key and presentation group key must be set as one - compound group key on the billable metric. - - quantity_conversion: Optional. Only valid for USAGE products. If provided, the quantity will be - converted using the provided conversion factor and operation. For example, if - the operation is "multiply" and the conversion factor is 100, then the quantity - will be multiplied by 100. This can be used in cases where data is sent in one - unit and priced in another. For example, data could be sent in MB and priced in - GB. In this case, the conversion factor would be 1024 and the operation would be - "divide". - - quantity_rounding: Optional. Only valid for USAGE products. If provided, the quantity will be - rounded using the provided rounding method and decimal places. For example, if - the method is "round up" and the decimal places is 0, then the quantity will be - rounded up to the nearest integer. - - tags: If not provided, defaults to product's current tags - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contract-pricing/products/update", - body=await async_maybe_transform( - { - "product_id": product_id, - "starting_at": starting_at, - "billable_metric_id": billable_metric_id, - "composite_product_ids": composite_product_ids, - "composite_tags": composite_tags, - "exclude_free_usage": exclude_free_usage, - "is_refundable": is_refundable, - "name": name, - "netsuite_internal_item_id": netsuite_internal_item_id, - "netsuite_overage_item_id": netsuite_overage_item_id, - "presentation_group_key": presentation_group_key, - "pricing_group_key": pricing_group_key, - "quantity_conversion": quantity_conversion, - "quantity_rounding": quantity_rounding, - "tags": tags, - }, - product_update_params.ProductUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ProductUpdateResponse, - ) - - def list( - self, - *, - limit: int | Omit = omit, - next_page: str | Omit = omit, - archive_filter: Literal["ARCHIVED", "NOT_ARCHIVED", "ALL"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[ProductListResponse, AsyncCursorPage[ProductListResponse]]: - """ - Get a paginated list of all products in your organization with their complete - configuration, version history, and metadata. By default excludes archived - products unless explicitly requested via the `archive_filter` parameter. - - Args: - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - archive_filter: Filter options for the product list. If not provided, defaults to not archived. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/contract-pricing/products/list", - page=AsyncCursorPage[ProductListResponse], - body=maybe_transform({"archive_filter": archive_filter}, product_list_params.ProductListParams), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - product_list_params.ProductListParams, - ), - ), - model=ProductListResponse, - method="post", - ) - - async def archive( - self, - *, - product_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ProductArchiveResponse: - """Archive a product. - - Any current rate cards associated with this product will - continue to function as normal. However, it will no longer be available as an - option for newly created rates. Once you archive a product, you can still - retrieve it in the UI and API, but you cannot unarchive it. - - Args: - product_id: ID of the product to be archived - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contract-pricing/products/archive", - body=await async_maybe_transform({"product_id": product_id}, product_archive_params.ProductArchiveParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ProductArchiveResponse, - ) - - -class ProductsResourceWithRawResponse: - def __init__(self, products: ProductsResource) -> None: - self._products = products - - self.create = to_raw_response_wrapper( - products.create, - ) - self.retrieve = to_raw_response_wrapper( - products.retrieve, - ) - self.update = to_raw_response_wrapper( - products.update, - ) - self.list = to_raw_response_wrapper( - products.list, - ) - self.archive = to_raw_response_wrapper( - products.archive, - ) - - -class AsyncProductsResourceWithRawResponse: - def __init__(self, products: AsyncProductsResource) -> None: - self._products = products - - self.create = async_to_raw_response_wrapper( - products.create, - ) - self.retrieve = async_to_raw_response_wrapper( - products.retrieve, - ) - self.update = async_to_raw_response_wrapper( - products.update, - ) - self.list = async_to_raw_response_wrapper( - products.list, - ) - self.archive = async_to_raw_response_wrapper( - products.archive, - ) - - -class ProductsResourceWithStreamingResponse: - def __init__(self, products: ProductsResource) -> None: - self._products = products - - self.create = to_streamed_response_wrapper( - products.create, - ) - self.retrieve = to_streamed_response_wrapper( - products.retrieve, - ) - self.update = to_streamed_response_wrapper( - products.update, - ) - self.list = to_streamed_response_wrapper( - products.list, - ) - self.archive = to_streamed_response_wrapper( - products.archive, - ) - - -class AsyncProductsResourceWithStreamingResponse: - def __init__(self, products: AsyncProductsResource) -> None: - self._products = products - - self.create = async_to_streamed_response_wrapper( - products.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - products.retrieve, - ) - self.update = async_to_streamed_response_wrapper( - products.update, - ) - self.list = async_to_streamed_response_wrapper( - products.list, - ) - self.archive = async_to_streamed_response_wrapper( - products.archive, - ) diff --git a/src/metronome/resources/v1/contracts/rate_cards/__init__.py b/src/metronome/resources/v1/contracts/rate_cards/__init__.py deleted file mode 100644 index 5fa4b5168..000000000 --- a/src/metronome/resources/v1/contracts/rate_cards/__init__.py +++ /dev/null @@ -1,61 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .rates import ( - RatesResource, - AsyncRatesResource, - RatesResourceWithRawResponse, - AsyncRatesResourceWithRawResponse, - RatesResourceWithStreamingResponse, - AsyncRatesResourceWithStreamingResponse, -) -from .rate_cards import ( - RateCardsResource, - AsyncRateCardsResource, - RateCardsResourceWithRawResponse, - AsyncRateCardsResourceWithRawResponse, - RateCardsResourceWithStreamingResponse, - AsyncRateCardsResourceWithStreamingResponse, -) -from .product_orders import ( - ProductOrdersResource, - AsyncProductOrdersResource, - ProductOrdersResourceWithRawResponse, - AsyncProductOrdersResourceWithRawResponse, - ProductOrdersResourceWithStreamingResponse, - AsyncProductOrdersResourceWithStreamingResponse, -) -from .named_schedules import ( - NamedSchedulesResource, - AsyncNamedSchedulesResource, - NamedSchedulesResourceWithRawResponse, - AsyncNamedSchedulesResourceWithRawResponse, - NamedSchedulesResourceWithStreamingResponse, - AsyncNamedSchedulesResourceWithStreamingResponse, -) - -__all__ = [ - "ProductOrdersResource", - "AsyncProductOrdersResource", - "ProductOrdersResourceWithRawResponse", - "AsyncProductOrdersResourceWithRawResponse", - "ProductOrdersResourceWithStreamingResponse", - "AsyncProductOrdersResourceWithStreamingResponse", - "RatesResource", - "AsyncRatesResource", - "RatesResourceWithRawResponse", - "AsyncRatesResourceWithRawResponse", - "RatesResourceWithStreamingResponse", - "AsyncRatesResourceWithStreamingResponse", - "NamedSchedulesResource", - "AsyncNamedSchedulesResource", - "NamedSchedulesResourceWithRawResponse", - "AsyncNamedSchedulesResourceWithRawResponse", - "NamedSchedulesResourceWithStreamingResponse", - "AsyncNamedSchedulesResourceWithStreamingResponse", - "RateCardsResource", - "AsyncRateCardsResource", - "RateCardsResourceWithRawResponse", - "AsyncRateCardsResourceWithRawResponse", - "RateCardsResourceWithStreamingResponse", - "AsyncRateCardsResourceWithStreamingResponse", -] diff --git a/src/metronome/resources/v1/contracts/rate_cards/named_schedules.py b/src/metronome/resources/v1/contracts/rate_cards/named_schedules.py deleted file mode 100644 index c9b5662ad..000000000 --- a/src/metronome/resources/v1/contracts/rate_cards/named_schedules.py +++ /dev/null @@ -1,350 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime - -import httpx - -from ....._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from ....._utils import maybe_transform, async_maybe_transform -from ....._compat import cached_property -from ....._resource import SyncAPIResource, AsyncAPIResource -from ....._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ....._base_client import make_request_options -from .....types.v1.contracts.rate_cards import named_schedule_update_params, named_schedule_retrieve_params -from .....types.v1.contracts.rate_cards.named_schedule_retrieve_response import NamedScheduleRetrieveResponse - -__all__ = ["NamedSchedulesResource", "AsyncNamedSchedulesResource"] - - -class NamedSchedulesResource(SyncAPIResource): - """Named schedules are used for storing custom data that can change over time. - - Named schedules are often used in custom pricing logic. - """ - - @cached_property - def with_raw_response(self) -> NamedSchedulesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return NamedSchedulesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> NamedSchedulesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return NamedSchedulesResourceWithStreamingResponse(self) - - def retrieve( - self, - *, - contract_id: str, - customer_id: str, - schedule_name: str, - covering_date: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> NamedScheduleRetrieveResponse: - """Get a named schedule for the given contract. - - This endpoint's availability is - dependent on your client's configuration. - - Args: - contract_id: ID of the contract whose named schedule is to be retrieved - - customer_id: ID of the customer whose named schedule is to be retrieved - - schedule_name: The identifier for the schedule to be retrieved - - covering_date: If provided, at most one schedule segment will be returned (the one that covers - this date). If not provided, all segments will be returned. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contracts/getNamedSchedule", - body=maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - "schedule_name": schedule_name, - "covering_date": covering_date, - }, - named_schedule_retrieve_params.NamedScheduleRetrieveParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NamedScheduleRetrieveResponse, - ) - - def update( - self, - *, - contract_id: str, - customer_id: str, - schedule_name: str, - starting_at: Union[str, datetime], - value: object, - ending_before: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """Update a named schedule for the given contract. - - This endpoint's availability is - dependent on your client's configuration. - - Args: - contract_id: ID of the contract whose named schedule is to be updated - - customer_id: ID of the customer whose named schedule is to be updated - - schedule_name: The identifier for the schedule to be updated - - value: The value to set for the named schedule. The structure of this object is - specific to the named schedule. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._post( - "/v1/contracts/updateNamedSchedule", - body=maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - "schedule_name": schedule_name, - "starting_at": starting_at, - "value": value, - "ending_before": ending_before, - }, - named_schedule_update_params.NamedScheduleUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class AsyncNamedSchedulesResource(AsyncAPIResource): - """Named schedules are used for storing custom data that can change over time. - - Named schedules are often used in custom pricing logic. - """ - - @cached_property - def with_raw_response(self) -> AsyncNamedSchedulesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncNamedSchedulesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncNamedSchedulesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncNamedSchedulesResourceWithStreamingResponse(self) - - async def retrieve( - self, - *, - contract_id: str, - customer_id: str, - schedule_name: str, - covering_date: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> NamedScheduleRetrieveResponse: - """Get a named schedule for the given contract. - - This endpoint's availability is - dependent on your client's configuration. - - Args: - contract_id: ID of the contract whose named schedule is to be retrieved - - customer_id: ID of the customer whose named schedule is to be retrieved - - schedule_name: The identifier for the schedule to be retrieved - - covering_date: If provided, at most one schedule segment will be returned (the one that covers - this date). If not provided, all segments will be returned. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contracts/getNamedSchedule", - body=await async_maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - "schedule_name": schedule_name, - "covering_date": covering_date, - }, - named_schedule_retrieve_params.NamedScheduleRetrieveParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NamedScheduleRetrieveResponse, - ) - - async def update( - self, - *, - contract_id: str, - customer_id: str, - schedule_name: str, - starting_at: Union[str, datetime], - value: object, - ending_before: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """Update a named schedule for the given contract. - - This endpoint's availability is - dependent on your client's configuration. - - Args: - contract_id: ID of the contract whose named schedule is to be updated - - customer_id: ID of the customer whose named schedule is to be updated - - schedule_name: The identifier for the schedule to be updated - - value: The value to set for the named schedule. The structure of this object is - specific to the named schedule. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._post( - "/v1/contracts/updateNamedSchedule", - body=await async_maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - "schedule_name": schedule_name, - "starting_at": starting_at, - "value": value, - "ending_before": ending_before, - }, - named_schedule_update_params.NamedScheduleUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class NamedSchedulesResourceWithRawResponse: - def __init__(self, named_schedules: NamedSchedulesResource) -> None: - self._named_schedules = named_schedules - - self.retrieve = to_raw_response_wrapper( - named_schedules.retrieve, - ) - self.update = to_raw_response_wrapper( - named_schedules.update, - ) - - -class AsyncNamedSchedulesResourceWithRawResponse: - def __init__(self, named_schedules: AsyncNamedSchedulesResource) -> None: - self._named_schedules = named_schedules - - self.retrieve = async_to_raw_response_wrapper( - named_schedules.retrieve, - ) - self.update = async_to_raw_response_wrapper( - named_schedules.update, - ) - - -class NamedSchedulesResourceWithStreamingResponse: - def __init__(self, named_schedules: NamedSchedulesResource) -> None: - self._named_schedules = named_schedules - - self.retrieve = to_streamed_response_wrapper( - named_schedules.retrieve, - ) - self.update = to_streamed_response_wrapper( - named_schedules.update, - ) - - -class AsyncNamedSchedulesResourceWithStreamingResponse: - def __init__(self, named_schedules: AsyncNamedSchedulesResource) -> None: - self._named_schedules = named_schedules - - self.retrieve = async_to_streamed_response_wrapper( - named_schedules.retrieve, - ) - self.update = async_to_streamed_response_wrapper( - named_schedules.update, - ) diff --git a/src/metronome/resources/v1/contracts/rate_cards/product_orders.py b/src/metronome/resources/v1/contracts/rate_cards/product_orders.py deleted file mode 100644 index 5be93f5e1..000000000 --- a/src/metronome/resources/v1/contracts/rate_cards/product_orders.py +++ /dev/null @@ -1,292 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable - -import httpx - -from ....._types import Body, Query, Headers, NotGiven, SequenceNotStr, not_given -from ....._utils import maybe_transform, async_maybe_transform -from ....._compat import cached_property -from ....._resource import SyncAPIResource, AsyncAPIResource -from ....._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ....._base_client import make_request_options -from .....types.v1.contracts.rate_cards import product_order_set_params, product_order_update_params -from .....types.v1.contracts.rate_cards.product_order_set_response import ProductOrderSetResponse -from .....types.v1.contracts.rate_cards.product_order_update_response import ProductOrderUpdateResponse - -__all__ = ["ProductOrdersResource", "AsyncProductOrdersResource"] - - -class ProductOrdersResource(SyncAPIResource): - """Rate cards are used to define default pricing for products.""" - - @cached_property - def with_raw_response(self) -> ProductOrdersResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return ProductOrdersResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ProductOrdersResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return ProductOrdersResourceWithStreamingResponse(self) - - def update( - self, - *, - product_moves: Iterable[product_order_update_params.ProductMove], - rate_card_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ProductOrderUpdateResponse: - """ - The ordering of products on a rate card determines the order in which the - products will appear on customers' invoices. Use this endpoint to set the order - of specific products on the rate card by moving them relative to their current - location. - - Args: - rate_card_id: ID of the rate card to update - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contract-pricing/rate-cards/moveRateCardProducts", - body=maybe_transform( - { - "product_moves": product_moves, - "rate_card_id": rate_card_id, - }, - product_order_update_params.ProductOrderUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ProductOrderUpdateResponse, - ) - - def set( - self, - *, - product_order: SequenceNotStr[str], - rate_card_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ProductOrderSetResponse: - """ - The ordering of products on a rate card determines the order in which the - products will appear on customers' invoices. Use this endpoint to set the order - of products on the rate card. - - Args: - rate_card_id: ID of the rate card to update - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contract-pricing/rate-cards/setRateCardProductsOrder", - body=maybe_transform( - { - "product_order": product_order, - "rate_card_id": rate_card_id, - }, - product_order_set_params.ProductOrderSetParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ProductOrderSetResponse, - ) - - -class AsyncProductOrdersResource(AsyncAPIResource): - """Rate cards are used to define default pricing for products.""" - - @cached_property - def with_raw_response(self) -> AsyncProductOrdersResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncProductOrdersResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncProductOrdersResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncProductOrdersResourceWithStreamingResponse(self) - - async def update( - self, - *, - product_moves: Iterable[product_order_update_params.ProductMove], - rate_card_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ProductOrderUpdateResponse: - """ - The ordering of products on a rate card determines the order in which the - products will appear on customers' invoices. Use this endpoint to set the order - of specific products on the rate card by moving them relative to their current - location. - - Args: - rate_card_id: ID of the rate card to update - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contract-pricing/rate-cards/moveRateCardProducts", - body=await async_maybe_transform( - { - "product_moves": product_moves, - "rate_card_id": rate_card_id, - }, - product_order_update_params.ProductOrderUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ProductOrderUpdateResponse, - ) - - async def set( - self, - *, - product_order: SequenceNotStr[str], - rate_card_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ProductOrderSetResponse: - """ - The ordering of products on a rate card determines the order in which the - products will appear on customers' invoices. Use this endpoint to set the order - of products on the rate card. - - Args: - rate_card_id: ID of the rate card to update - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contract-pricing/rate-cards/setRateCardProductsOrder", - body=await async_maybe_transform( - { - "product_order": product_order, - "rate_card_id": rate_card_id, - }, - product_order_set_params.ProductOrderSetParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ProductOrderSetResponse, - ) - - -class ProductOrdersResourceWithRawResponse: - def __init__(self, product_orders: ProductOrdersResource) -> None: - self._product_orders = product_orders - - self.update = to_raw_response_wrapper( - product_orders.update, - ) - self.set = to_raw_response_wrapper( - product_orders.set, - ) - - -class AsyncProductOrdersResourceWithRawResponse: - def __init__(self, product_orders: AsyncProductOrdersResource) -> None: - self._product_orders = product_orders - - self.update = async_to_raw_response_wrapper( - product_orders.update, - ) - self.set = async_to_raw_response_wrapper( - product_orders.set, - ) - - -class ProductOrdersResourceWithStreamingResponse: - def __init__(self, product_orders: ProductOrdersResource) -> None: - self._product_orders = product_orders - - self.update = to_streamed_response_wrapper( - product_orders.update, - ) - self.set = to_streamed_response_wrapper( - product_orders.set, - ) - - -class AsyncProductOrdersResourceWithStreamingResponse: - def __init__(self, product_orders: AsyncProductOrdersResource) -> None: - self._product_orders = product_orders - - self.update = async_to_streamed_response_wrapper( - product_orders.update, - ) - self.set = async_to_streamed_response_wrapper( - product_orders.set, - ) diff --git a/src/metronome/resources/v1/contracts/rate_cards/rate_cards.py b/src/metronome/resources/v1/contracts/rate_cards/rate_cards.py deleted file mode 100644 index 023d181fa..000000000 --- a/src/metronome/resources/v1/contracts/rate_cards/rate_cards.py +++ /dev/null @@ -1,1111 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable -from datetime import datetime - -import httpx - -from .rates import ( - RatesResource, - AsyncRatesResource, - RatesResourceWithRawResponse, - AsyncRatesResourceWithRawResponse, - RatesResourceWithStreamingResponse, - AsyncRatesResourceWithStreamingResponse, -) -from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ....._utils import maybe_transform, async_maybe_transform -from ....._compat import cached_property -from ....._resource import SyncAPIResource, AsyncAPIResource -from ....._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from .....pagination import SyncCursorPage, AsyncCursorPage -from .product_orders import ( - ProductOrdersResource, - AsyncProductOrdersResource, - ProductOrdersResourceWithRawResponse, - AsyncProductOrdersResourceWithRawResponse, - ProductOrdersResourceWithStreamingResponse, - AsyncProductOrdersResourceWithStreamingResponse, -) -from .named_schedules import ( - NamedSchedulesResource, - AsyncNamedSchedulesResource, - NamedSchedulesResourceWithRawResponse, - AsyncNamedSchedulesResourceWithRawResponse, - NamedSchedulesResourceWithStreamingResponse, - AsyncNamedSchedulesResourceWithStreamingResponse, -) -from ....._base_client import AsyncPaginator, make_request_options -from .....types.v1.contracts import ( - rate_card_list_params, - rate_card_create_params, - rate_card_update_params, - rate_card_archive_params, - rate_card_retrieve_params, - rate_card_retrieve_rate_schedule_params, -) -from .....types.v1.contracts.rate_card_list_response import RateCardListResponse -from .....types.v1.contracts.rate_card_create_response import RateCardCreateResponse -from .....types.v1.contracts.rate_card_update_response import RateCardUpdateResponse -from .....types.v1.contracts.rate_card_archive_response import RateCardArchiveResponse -from .....types.v1.contracts.rate_card_retrieve_response import RateCardRetrieveResponse -from .....types.v1.contracts.rate_card_retrieve_rate_schedule_response import RateCardRetrieveRateScheduleResponse - -__all__ = ["RateCardsResource", "AsyncRateCardsResource"] - - -class RateCardsResource(SyncAPIResource): - """Rate cards are used to define default pricing for products.""" - - @cached_property - def product_orders(self) -> ProductOrdersResource: - """Rate cards are used to define default pricing for products.""" - return ProductOrdersResource(self._client) - - @cached_property - def rates(self) -> RatesResource: - """Rate cards are used to define default pricing for products.""" - return RatesResource(self._client) - - @cached_property - def named_schedules(self) -> NamedSchedulesResource: - """Named schedules are used for storing custom data that can change over time. - - Named schedules are often used in custom pricing logic. - """ - return NamedSchedulesResource(self._client) - - @cached_property - def with_raw_response(self) -> RateCardsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return RateCardsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> RateCardsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return RateCardsResourceWithStreamingResponse(self) - - def create( - self, - *, - name: str, - aliases: Iterable[rate_card_create_params.Alias] | Omit = omit, - credit_type_conversions: Iterable[rate_card_create_params.CreditTypeConversion] | Omit = omit, - custom_fields: Dict[str, str] | Omit = omit, - description: str | Omit = omit, - fiat_credit_type_id: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RateCardCreateResponse: - """In Metronome, the rate card is the central location for your pricing. - - Rate cards - were built with new product launches and pricing changes in mind - you can - update your products and pricing in one place, and that change will be - automatically propagated across your customer cohorts. Most clients need only - maintain one or a few rate cards within Metronome. - - ### Use this endpoint to: - - - Create a rate card with a name and description - - Define the rate card's single underlying fiat currency, and any number of - conversion rates between that fiat currency and custom pricing units. You can - then add products and associated rates in the fiat currency or custom pricing - unit for which you have defined a conversion rate. - - Set aliases for the rate card. Aliases are human-readable names that you can - use in the place of the id of the rate card when provisioning a customer's - contract. By using an alias, you can easily create a contract and provision a - customer by choosing the paygo rate card, without storing the rate card id in - your internal systems. This is helpful when launching a new rate card for - paygo customers, you can update the alias for paygo to be scheduled to be - assigned to the new rate card without updating your code. - - ### Key response fields: - - - The ID of the rate card you just created - - ### Usage guidelines: - - - After creating a rate card, you can now use the addRate or addRates endpoints - to add products and their prices to it - - A rate card alias can only be used by one rate card at a time. If you create a - contract with a rate card alias that is already in use by another rate card, - the original rate card's alias schedule will be updated. The alias will - reference the rate card to which it was most recently assigned. - - Args: - name: Used only in UI/API. It is not exposed to end customers. - - aliases: Reference this alias when creating a contract. If the same alias is assigned to - multiple rate cards, it will reference the rate card to which it was most - recently assigned. It is not exposed to end customers. - - credit_type_conversions: Required when using custom pricing units in rates. - - custom_fields: Custom fields to be added eg. { "key1": "value1", "key2": "value2" } - - fiat_credit_type_id: The Metronome ID of the credit type to associate with the rate card, defaults to - USD (cents) if not passed. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contract-pricing/rate-cards/create", - body=maybe_transform( - { - "name": name, - "aliases": aliases, - "credit_type_conversions": credit_type_conversions, - "custom_fields": custom_fields, - "description": description, - "fiat_credit_type_id": fiat_credit_type_id, - }, - rate_card_create_params.RateCardCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RateCardCreateResponse, - ) - - def retrieve( - self, - *, - id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RateCardRetrieveResponse: - """Return details for a specific rate card including name, description, and - aliases. - - This endpoint does not return rates - use the dedicated getRates or - getRateSchedule endpoints to understand the rates on a rate card. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contract-pricing/rate-cards/get", - body=maybe_transform({"id": id}, rate_card_retrieve_params.RateCardRetrieveParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RateCardRetrieveResponse, - ) - - def update( - self, - *, - rate_card_id: str, - aliases: Iterable[rate_card_update_params.Alias] | Omit = omit, - description: str | Omit = omit, - name: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RateCardUpdateResponse: - """ - Update the metadata properties of an existing rate card, including its name, - description, and aliases. This endpoint is designed for managing rate card - identity and reference aliases rather than modifying pricing rates. - - Modifies the descriptive properties and alias configuration of a rate card - without affecting the underlying pricing rates or schedules. This allows you to - update how a rate card is identified and referenced throughout your system. - - ### Use this endpoint to: - - - Rate card renaming: Update display names or descriptions for organizational - clarity - - Alias management: Add, modify, or schedule alias transitions for seamless rate - card migrations - - Documentation updates: Keep rate card descriptions current with business - context - - Self-serve provisioning setup: Configure aliases to enable code-free rate card - transitions - - #### Active contract impact: - - - Alias changes: Already-created contracts continue using their originally - assigned rate cards. - - Other changes made using this endpoint will only impact the Metronome UI. - - #### Grandfathering existing PLG customer pricing: - - - Rate card aliases support scheduled transitions, enabling seamless rate card - migrations for new customers, allowing existing customers to be grandfathered - into their existing prices without code. Note that there are multiple - mechanisms to support grandfathering in Metronome. - - #### How scheduled aliases work for PLG grandfathering: - - Initial setup: - - - Add alias to current rate card: Assign a stable alias (e.g., - "standard-pricing") to your active rate card - - Reference alias during contract creation: Configure your self-serve workflow - to create contracts using `rate_card_alias` instead of direct `rate_card_id` - - Automatic resolution: New contracts referencing the alias automatically - resolve to the rate card associated with the alias at the point in time of - provisioning - - #### Grandfathering process: - - - Create new rate card: Build your new rate card with updated pricing structure - - Schedule alias transition: Add the same alias to the new rate card with a - `starting_at` timestamp - - Automatic cutover: Starting at the scheduled time, new contracts created in - your PLG workflow using that alias will automatically reference the new rate - card - - Args: - rate_card_id: ID of the rate card to update - - aliases: Reference this alias when creating a contract. If the same alias is assigned to - multiple rate cards, it will reference the rate card to which it was most - recently assigned. It is not exposed to end customers. - - name: Used only in UI/API. It is not exposed to end customers. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contract-pricing/rate-cards/update", - body=maybe_transform( - { - "rate_card_id": rate_card_id, - "aliases": aliases, - "description": description, - "name": name, - }, - rate_card_update_params.RateCardUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RateCardUpdateResponse, - ) - - def list( - self, - *, - limit: int | Omit = omit, - next_page: str | Omit = omit, - body: object | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[RateCardListResponse]: - """List all rate cards. - - Returns rate card IDs, names, descriptions, aliases, and - other details. To view the rates associated with a given rate card, use the - getRates or getRateSchedule endpoints. - - Args: - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/contract-pricing/rate-cards/list", - page=SyncCursorPage[RateCardListResponse], - body=maybe_transform(body, rate_card_list_params.RateCardListParams), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - rate_card_list_params.RateCardListParams, - ), - ), - model=RateCardListResponse, - method="post", - ) - - def archive( - self, - *, - id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RateCardArchiveResponse: - """ - Permanently disable a rate card by archiving it, preventing use in new contracts - while preserving existing contract pricing. Use this when retiring old pricing - models, consolidating rate cards, or removing outdated pricing structures. - Returns the archived rate card ID and stops the rate card from appearing in - contract creation workflows. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contract-pricing/rate-cards/archive", - body=maybe_transform({"id": id}, rate_card_archive_params.RateCardArchiveParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RateCardArchiveResponse, - ) - - def retrieve_rate_schedule( - self, - *, - rate_card_id: str, - starting_at: Union[str, datetime], - limit: int | Omit = omit, - next_page: str | Omit = omit, - ending_before: Union[str, datetime] | Omit = omit, - selectors: Iterable[rate_card_retrieve_rate_schedule_params.Selector] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RateCardRetrieveRateScheduleResponse: - """A rate card defines the prices that you charge for your products. - - Rate cards - support scheduled changes over time, to allow you to easily roll out pricing - changes and new product launches across your customer base. Use this endpoint to - understand the rate schedule `starting_at` a given date, optionally filtering - the list of rates returned based on product id or pricing group values. For - example, you may want to display a schedule of upcoming price changes for a - given product in your product experience - use this endpoint to fetch that - information from its source of truth in Metronome. - - If you want to understand the rates for a specific customer's contract, - inclusive of contract-level overrides, use the `getContractRateSchedule` - endpoint. - - Args: - rate_card_id: ID of the rate card to get the schedule for - - starting_at: inclusive starting point for the rates schedule - - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - ending_before: optional exclusive end date for the rates schedule. When not specified rates - will show all future schedule segments. - - selectors: List of rate selectors, rates matching ANY of the selector will be included in - the response Passing no selectors will result in all rates being returned. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contract-pricing/rate-cards/getRateSchedule", - body=maybe_transform( - { - "rate_card_id": rate_card_id, - "starting_at": starting_at, - "ending_before": ending_before, - "selectors": selectors, - }, - rate_card_retrieve_rate_schedule_params.RateCardRetrieveRateScheduleParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - rate_card_retrieve_rate_schedule_params.RateCardRetrieveRateScheduleParams, - ), - ), - cast_to=RateCardRetrieveRateScheduleResponse, - ) - - -class AsyncRateCardsResource(AsyncAPIResource): - """Rate cards are used to define default pricing for products.""" - - @cached_property - def product_orders(self) -> AsyncProductOrdersResource: - """Rate cards are used to define default pricing for products.""" - return AsyncProductOrdersResource(self._client) - - @cached_property - def rates(self) -> AsyncRatesResource: - """Rate cards are used to define default pricing for products.""" - return AsyncRatesResource(self._client) - - @cached_property - def named_schedules(self) -> AsyncNamedSchedulesResource: - """Named schedules are used for storing custom data that can change over time. - - Named schedules are often used in custom pricing logic. - """ - return AsyncNamedSchedulesResource(self._client) - - @cached_property - def with_raw_response(self) -> AsyncRateCardsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncRateCardsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncRateCardsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncRateCardsResourceWithStreamingResponse(self) - - async def create( - self, - *, - name: str, - aliases: Iterable[rate_card_create_params.Alias] | Omit = omit, - credit_type_conversions: Iterable[rate_card_create_params.CreditTypeConversion] | Omit = omit, - custom_fields: Dict[str, str] | Omit = omit, - description: str | Omit = omit, - fiat_credit_type_id: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RateCardCreateResponse: - """In Metronome, the rate card is the central location for your pricing. - - Rate cards - were built with new product launches and pricing changes in mind - you can - update your products and pricing in one place, and that change will be - automatically propagated across your customer cohorts. Most clients need only - maintain one or a few rate cards within Metronome. - - ### Use this endpoint to: - - - Create a rate card with a name and description - - Define the rate card's single underlying fiat currency, and any number of - conversion rates between that fiat currency and custom pricing units. You can - then add products and associated rates in the fiat currency or custom pricing - unit for which you have defined a conversion rate. - - Set aliases for the rate card. Aliases are human-readable names that you can - use in the place of the id of the rate card when provisioning a customer's - contract. By using an alias, you can easily create a contract and provision a - customer by choosing the paygo rate card, without storing the rate card id in - your internal systems. This is helpful when launching a new rate card for - paygo customers, you can update the alias for paygo to be scheduled to be - assigned to the new rate card without updating your code. - - ### Key response fields: - - - The ID of the rate card you just created - - ### Usage guidelines: - - - After creating a rate card, you can now use the addRate or addRates endpoints - to add products and their prices to it - - A rate card alias can only be used by one rate card at a time. If you create a - contract with a rate card alias that is already in use by another rate card, - the original rate card's alias schedule will be updated. The alias will - reference the rate card to which it was most recently assigned. - - Args: - name: Used only in UI/API. It is not exposed to end customers. - - aliases: Reference this alias when creating a contract. If the same alias is assigned to - multiple rate cards, it will reference the rate card to which it was most - recently assigned. It is not exposed to end customers. - - credit_type_conversions: Required when using custom pricing units in rates. - - custom_fields: Custom fields to be added eg. { "key1": "value1", "key2": "value2" } - - fiat_credit_type_id: The Metronome ID of the credit type to associate with the rate card, defaults to - USD (cents) if not passed. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contract-pricing/rate-cards/create", - body=await async_maybe_transform( - { - "name": name, - "aliases": aliases, - "credit_type_conversions": credit_type_conversions, - "custom_fields": custom_fields, - "description": description, - "fiat_credit_type_id": fiat_credit_type_id, - }, - rate_card_create_params.RateCardCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RateCardCreateResponse, - ) - - async def retrieve( - self, - *, - id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RateCardRetrieveResponse: - """Return details for a specific rate card including name, description, and - aliases. - - This endpoint does not return rates - use the dedicated getRates or - getRateSchedule endpoints to understand the rates on a rate card. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contract-pricing/rate-cards/get", - body=await async_maybe_transform({"id": id}, rate_card_retrieve_params.RateCardRetrieveParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RateCardRetrieveResponse, - ) - - async def update( - self, - *, - rate_card_id: str, - aliases: Iterable[rate_card_update_params.Alias] | Omit = omit, - description: str | Omit = omit, - name: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RateCardUpdateResponse: - """ - Update the metadata properties of an existing rate card, including its name, - description, and aliases. This endpoint is designed for managing rate card - identity and reference aliases rather than modifying pricing rates. - - Modifies the descriptive properties and alias configuration of a rate card - without affecting the underlying pricing rates or schedules. This allows you to - update how a rate card is identified and referenced throughout your system. - - ### Use this endpoint to: - - - Rate card renaming: Update display names or descriptions for organizational - clarity - - Alias management: Add, modify, or schedule alias transitions for seamless rate - card migrations - - Documentation updates: Keep rate card descriptions current with business - context - - Self-serve provisioning setup: Configure aliases to enable code-free rate card - transitions - - #### Active contract impact: - - - Alias changes: Already-created contracts continue using their originally - assigned rate cards. - - Other changes made using this endpoint will only impact the Metronome UI. - - #### Grandfathering existing PLG customer pricing: - - - Rate card aliases support scheduled transitions, enabling seamless rate card - migrations for new customers, allowing existing customers to be grandfathered - into their existing prices without code. Note that there are multiple - mechanisms to support grandfathering in Metronome. - - #### How scheduled aliases work for PLG grandfathering: - - Initial setup: - - - Add alias to current rate card: Assign a stable alias (e.g., - "standard-pricing") to your active rate card - - Reference alias during contract creation: Configure your self-serve workflow - to create contracts using `rate_card_alias` instead of direct `rate_card_id` - - Automatic resolution: New contracts referencing the alias automatically - resolve to the rate card associated with the alias at the point in time of - provisioning - - #### Grandfathering process: - - - Create new rate card: Build your new rate card with updated pricing structure - - Schedule alias transition: Add the same alias to the new rate card with a - `starting_at` timestamp - - Automatic cutover: Starting at the scheduled time, new contracts created in - your PLG workflow using that alias will automatically reference the new rate - card - - Args: - rate_card_id: ID of the rate card to update - - aliases: Reference this alias when creating a contract. If the same alias is assigned to - multiple rate cards, it will reference the rate card to which it was most - recently assigned. It is not exposed to end customers. - - name: Used only in UI/API. It is not exposed to end customers. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contract-pricing/rate-cards/update", - body=await async_maybe_transform( - { - "rate_card_id": rate_card_id, - "aliases": aliases, - "description": description, - "name": name, - }, - rate_card_update_params.RateCardUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RateCardUpdateResponse, - ) - - def list( - self, - *, - limit: int | Omit = omit, - next_page: str | Omit = omit, - body: object | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[RateCardListResponse, AsyncCursorPage[RateCardListResponse]]: - """List all rate cards. - - Returns rate card IDs, names, descriptions, aliases, and - other details. To view the rates associated with a given rate card, use the - getRates or getRateSchedule endpoints. - - Args: - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/contract-pricing/rate-cards/list", - page=AsyncCursorPage[RateCardListResponse], - body=maybe_transform(body, rate_card_list_params.RateCardListParams), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - rate_card_list_params.RateCardListParams, - ), - ), - model=RateCardListResponse, - method="post", - ) - - async def archive( - self, - *, - id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RateCardArchiveResponse: - """ - Permanently disable a rate card by archiving it, preventing use in new contracts - while preserving existing contract pricing. Use this when retiring old pricing - models, consolidating rate cards, or removing outdated pricing structures. - Returns the archived rate card ID and stops the rate card from appearing in - contract creation workflows. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contract-pricing/rate-cards/archive", - body=await async_maybe_transform({"id": id}, rate_card_archive_params.RateCardArchiveParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RateCardArchiveResponse, - ) - - async def retrieve_rate_schedule( - self, - *, - rate_card_id: str, - starting_at: Union[str, datetime], - limit: int | Omit = omit, - next_page: str | Omit = omit, - ending_before: Union[str, datetime] | Omit = omit, - selectors: Iterable[rate_card_retrieve_rate_schedule_params.Selector] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RateCardRetrieveRateScheduleResponse: - """A rate card defines the prices that you charge for your products. - - Rate cards - support scheduled changes over time, to allow you to easily roll out pricing - changes and new product launches across your customer base. Use this endpoint to - understand the rate schedule `starting_at` a given date, optionally filtering - the list of rates returned based on product id or pricing group values. For - example, you may want to display a schedule of upcoming price changes for a - given product in your product experience - use this endpoint to fetch that - information from its source of truth in Metronome. - - If you want to understand the rates for a specific customer's contract, - inclusive of contract-level overrides, use the `getContractRateSchedule` - endpoint. - - Args: - rate_card_id: ID of the rate card to get the schedule for - - starting_at: inclusive starting point for the rates schedule - - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - ending_before: optional exclusive end date for the rates schedule. When not specified rates - will show all future schedule segments. - - selectors: List of rate selectors, rates matching ANY of the selector will be included in - the response Passing no selectors will result in all rates being returned. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contract-pricing/rate-cards/getRateSchedule", - body=await async_maybe_transform( - { - "rate_card_id": rate_card_id, - "starting_at": starting_at, - "ending_before": ending_before, - "selectors": selectors, - }, - rate_card_retrieve_rate_schedule_params.RateCardRetrieveRateScheduleParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - rate_card_retrieve_rate_schedule_params.RateCardRetrieveRateScheduleParams, - ), - ), - cast_to=RateCardRetrieveRateScheduleResponse, - ) - - -class RateCardsResourceWithRawResponse: - def __init__(self, rate_cards: RateCardsResource) -> None: - self._rate_cards = rate_cards - - self.create = to_raw_response_wrapper( - rate_cards.create, - ) - self.retrieve = to_raw_response_wrapper( - rate_cards.retrieve, - ) - self.update = to_raw_response_wrapper( - rate_cards.update, - ) - self.list = to_raw_response_wrapper( - rate_cards.list, - ) - self.archive = to_raw_response_wrapper( - rate_cards.archive, - ) - self.retrieve_rate_schedule = to_raw_response_wrapper( - rate_cards.retrieve_rate_schedule, - ) - - @cached_property - def product_orders(self) -> ProductOrdersResourceWithRawResponse: - """Rate cards are used to define default pricing for products.""" - return ProductOrdersResourceWithRawResponse(self._rate_cards.product_orders) - - @cached_property - def rates(self) -> RatesResourceWithRawResponse: - """Rate cards are used to define default pricing for products.""" - return RatesResourceWithRawResponse(self._rate_cards.rates) - - @cached_property - def named_schedules(self) -> NamedSchedulesResourceWithRawResponse: - """Named schedules are used for storing custom data that can change over time. - - Named schedules are often used in custom pricing logic. - """ - return NamedSchedulesResourceWithRawResponse(self._rate_cards.named_schedules) - - -class AsyncRateCardsResourceWithRawResponse: - def __init__(self, rate_cards: AsyncRateCardsResource) -> None: - self._rate_cards = rate_cards - - self.create = async_to_raw_response_wrapper( - rate_cards.create, - ) - self.retrieve = async_to_raw_response_wrapper( - rate_cards.retrieve, - ) - self.update = async_to_raw_response_wrapper( - rate_cards.update, - ) - self.list = async_to_raw_response_wrapper( - rate_cards.list, - ) - self.archive = async_to_raw_response_wrapper( - rate_cards.archive, - ) - self.retrieve_rate_schedule = async_to_raw_response_wrapper( - rate_cards.retrieve_rate_schedule, - ) - - @cached_property - def product_orders(self) -> AsyncProductOrdersResourceWithRawResponse: - """Rate cards are used to define default pricing for products.""" - return AsyncProductOrdersResourceWithRawResponse(self._rate_cards.product_orders) - - @cached_property - def rates(self) -> AsyncRatesResourceWithRawResponse: - """Rate cards are used to define default pricing for products.""" - return AsyncRatesResourceWithRawResponse(self._rate_cards.rates) - - @cached_property - def named_schedules(self) -> AsyncNamedSchedulesResourceWithRawResponse: - """Named schedules are used for storing custom data that can change over time. - - Named schedules are often used in custom pricing logic. - """ - return AsyncNamedSchedulesResourceWithRawResponse(self._rate_cards.named_schedules) - - -class RateCardsResourceWithStreamingResponse: - def __init__(self, rate_cards: RateCardsResource) -> None: - self._rate_cards = rate_cards - - self.create = to_streamed_response_wrapper( - rate_cards.create, - ) - self.retrieve = to_streamed_response_wrapper( - rate_cards.retrieve, - ) - self.update = to_streamed_response_wrapper( - rate_cards.update, - ) - self.list = to_streamed_response_wrapper( - rate_cards.list, - ) - self.archive = to_streamed_response_wrapper( - rate_cards.archive, - ) - self.retrieve_rate_schedule = to_streamed_response_wrapper( - rate_cards.retrieve_rate_schedule, - ) - - @cached_property - def product_orders(self) -> ProductOrdersResourceWithStreamingResponse: - """Rate cards are used to define default pricing for products.""" - return ProductOrdersResourceWithStreamingResponse(self._rate_cards.product_orders) - - @cached_property - def rates(self) -> RatesResourceWithStreamingResponse: - """Rate cards are used to define default pricing for products.""" - return RatesResourceWithStreamingResponse(self._rate_cards.rates) - - @cached_property - def named_schedules(self) -> NamedSchedulesResourceWithStreamingResponse: - """Named schedules are used for storing custom data that can change over time. - - Named schedules are often used in custom pricing logic. - """ - return NamedSchedulesResourceWithStreamingResponse(self._rate_cards.named_schedules) - - -class AsyncRateCardsResourceWithStreamingResponse: - def __init__(self, rate_cards: AsyncRateCardsResource) -> None: - self._rate_cards = rate_cards - - self.create = async_to_streamed_response_wrapper( - rate_cards.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - rate_cards.retrieve, - ) - self.update = async_to_streamed_response_wrapper( - rate_cards.update, - ) - self.list = async_to_streamed_response_wrapper( - rate_cards.list, - ) - self.archive = async_to_streamed_response_wrapper( - rate_cards.archive, - ) - self.retrieve_rate_schedule = async_to_streamed_response_wrapper( - rate_cards.retrieve_rate_schedule, - ) - - @cached_property - def product_orders(self) -> AsyncProductOrdersResourceWithStreamingResponse: - """Rate cards are used to define default pricing for products.""" - return AsyncProductOrdersResourceWithStreamingResponse(self._rate_cards.product_orders) - - @cached_property - def rates(self) -> AsyncRatesResourceWithStreamingResponse: - """Rate cards are used to define default pricing for products.""" - return AsyncRatesResourceWithStreamingResponse(self._rate_cards.rates) - - @cached_property - def named_schedules(self) -> AsyncNamedSchedulesResourceWithStreamingResponse: - """Named schedules are used for storing custom data that can change over time. - - Named schedules are often used in custom pricing logic. - """ - return AsyncNamedSchedulesResourceWithStreamingResponse(self._rate_cards.named_schedules) diff --git a/src/metronome/resources/v1/contracts/rate_cards/rates.py b/src/metronome/resources/v1/contracts/rate_cards/rates.py deleted file mode 100644 index 1c60f0b6e..000000000 --- a/src/metronome/resources/v1/contracts/rate_cards/rates.py +++ /dev/null @@ -1,562 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable -from datetime import datetime -from typing_extensions import Literal - -import httpx - -from ....._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ....._utils import maybe_transform, async_maybe_transform -from ....._compat import cached_property -from ....._resource import SyncAPIResource, AsyncAPIResource -from ....._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from .....pagination import SyncCursorPage, AsyncCursorPage -from ....._base_client import AsyncPaginator, make_request_options -from .....types.shared_params.tier import Tier -from .....types.v1.contracts.rate_cards import rate_add_params, rate_list_params, rate_add_many_params -from .....types.shared_params.commit_rate import CommitRate -from .....types.v1.contracts.rate_cards.rate_add_response import RateAddResponse -from .....types.v1.contracts.rate_cards.rate_list_response import RateListResponse -from .....types.v1.contracts.rate_cards.rate_add_many_response import RateAddManyResponse - -__all__ = ["RatesResource", "AsyncRatesResource"] - - -class RatesResource(SyncAPIResource): - """Rate cards are used to define default pricing for products.""" - - @cached_property - def with_raw_response(self) -> RatesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return RatesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> RatesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return RatesResourceWithStreamingResponse(self) - - def list( - self, - *, - at: Union[str, datetime], - rate_card_id: str, - limit: int | Omit = omit, - next_page: str | Omit = omit, - selectors: Iterable[rate_list_params.Selector] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[RateListResponse]: - """ - Understand the rate schedule at a given timestamp, optionally filtering the list - of rates returned based on properties such as `product_id` and - `pricing_group_values`. For example, you may want to display the current price - for a given product in your product experience - use this endpoint to fetch that - information from its source of truth in Metronome. - - If you want to understand the rates for a specific customer's contract, - inclusive of contract-level overrides, use the `getContractRateSchedule` - endpoint. - - Args: - at: inclusive starting point for the rates schedule - - rate_card_id: ID of the rate card to get the schedule for - - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - selectors: List of rate selectors, rates matching ANY of the selector will be included in - the response Passing no selectors will result in all rates being returned. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/contract-pricing/rate-cards/getRates", - page=SyncCursorPage[RateListResponse], - body=maybe_transform( - { - "at": at, - "rate_card_id": rate_card_id, - "selectors": selectors, - }, - rate_list_params.RateListParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - rate_list_params.RateListParams, - ), - ), - model=RateListResponse, - method="post", - ) - - def add( - self, - *, - entitled: bool, - product_id: str, - rate_card_id: str, - rate_type: Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "TIERED", "TIERED_PERCENTAGE", "CUSTOM"], - starting_at: Union[str, datetime], - billing_frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"] | Omit = omit, - commit_rate: CommitRate | Omit = omit, - credit_type_id: str | Omit = omit, - custom_rate: Dict[str, object] | Omit = omit, - ending_before: Union[str, datetime] | Omit = omit, - is_prorated: bool | Omit = omit, - price: float | Omit = omit, - pricing_group_values: Dict[str, str] | Omit = omit, - quantity: float | Omit = omit, - tiers: Iterable[Tier] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RateAddResponse: - """ - Add a new rate - - Args: - product_id: ID of the product to add a rate for - - rate_card_id: ID of the rate card to update - - starting_at: inclusive effective date - - billing_frequency: Optional. Frequency to bill subscriptions with. Required for subscription type - products with Flat rate. - - commit_rate: A distinct rate on the rate card. You can choose to use this rate rather than - list rate when consuming a credit or commit. - - credit_type_id: The Metronome ID of the credit type to associate with price, defaults to USD - (cents) if not passed. Used by all rate_types except type PERCENTAGE. PERCENTAGE - rates use the credit type of associated rates. - - custom_rate: Only set for CUSTOM rate_type. This field is interpreted by custom rate - processors. - - ending_before: exclusive end date - - is_prorated: Default proration configuration. Only valid for SUBSCRIPTION rate_type. Must be - set to true. - - price: Default price. For FLAT and SUBSCRIPTION rate_type, this must be >=0. For - PERCENTAGE rate_type, this is a decimal fraction, e.g. use 0.1 for 10%; this - must be >=0 and <=1. - - pricing_group_values: Optional. List of pricing group key value pairs which will be used to calculate - the price. - - quantity: Default quantity. For SUBSCRIPTION rate_type, this must be >=0. - - tiers: Only set for TIERED rate_type. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contract-pricing/rate-cards/addRate", - body=maybe_transform( - { - "entitled": entitled, - "product_id": product_id, - "rate_card_id": rate_card_id, - "rate_type": rate_type, - "starting_at": starting_at, - "billing_frequency": billing_frequency, - "commit_rate": commit_rate, - "credit_type_id": credit_type_id, - "custom_rate": custom_rate, - "ending_before": ending_before, - "is_prorated": is_prorated, - "price": price, - "pricing_group_values": pricing_group_values, - "quantity": quantity, - "tiers": tiers, - }, - rate_add_params.RateAddParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RateAddResponse, - ) - - def add_many( - self, - *, - rate_card_id: str, - rates: Iterable[rate_add_many_params.Rate], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RateAddManyResponse: - """ - Add new rates - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contract-pricing/rate-cards/addRates", - body=maybe_transform( - { - "rate_card_id": rate_card_id, - "rates": rates, - }, - rate_add_many_params.RateAddManyParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RateAddManyResponse, - ) - - -class AsyncRatesResource(AsyncAPIResource): - """Rate cards are used to define default pricing for products.""" - - @cached_property - def with_raw_response(self) -> AsyncRatesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncRatesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncRatesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncRatesResourceWithStreamingResponse(self) - - def list( - self, - *, - at: Union[str, datetime], - rate_card_id: str, - limit: int | Omit = omit, - next_page: str | Omit = omit, - selectors: Iterable[rate_list_params.Selector] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[RateListResponse, AsyncCursorPage[RateListResponse]]: - """ - Understand the rate schedule at a given timestamp, optionally filtering the list - of rates returned based on properties such as `product_id` and - `pricing_group_values`. For example, you may want to display the current price - for a given product in your product experience - use this endpoint to fetch that - information from its source of truth in Metronome. - - If you want to understand the rates for a specific customer's contract, - inclusive of contract-level overrides, use the `getContractRateSchedule` - endpoint. - - Args: - at: inclusive starting point for the rates schedule - - rate_card_id: ID of the rate card to get the schedule for - - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - selectors: List of rate selectors, rates matching ANY of the selector will be included in - the response Passing no selectors will result in all rates being returned. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/contract-pricing/rate-cards/getRates", - page=AsyncCursorPage[RateListResponse], - body=maybe_transform( - { - "at": at, - "rate_card_id": rate_card_id, - "selectors": selectors, - }, - rate_list_params.RateListParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - rate_list_params.RateListParams, - ), - ), - model=RateListResponse, - method="post", - ) - - async def add( - self, - *, - entitled: bool, - product_id: str, - rate_card_id: str, - rate_type: Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "TIERED", "TIERED_PERCENTAGE", "CUSTOM"], - starting_at: Union[str, datetime], - billing_frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"] | Omit = omit, - commit_rate: CommitRate | Omit = omit, - credit_type_id: str | Omit = omit, - custom_rate: Dict[str, object] | Omit = omit, - ending_before: Union[str, datetime] | Omit = omit, - is_prorated: bool | Omit = omit, - price: float | Omit = omit, - pricing_group_values: Dict[str, str] | Omit = omit, - quantity: float | Omit = omit, - tiers: Iterable[Tier] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RateAddResponse: - """ - Add a new rate - - Args: - product_id: ID of the product to add a rate for - - rate_card_id: ID of the rate card to update - - starting_at: inclusive effective date - - billing_frequency: Optional. Frequency to bill subscriptions with. Required for subscription type - products with Flat rate. - - commit_rate: A distinct rate on the rate card. You can choose to use this rate rather than - list rate when consuming a credit or commit. - - credit_type_id: The Metronome ID of the credit type to associate with price, defaults to USD - (cents) if not passed. Used by all rate_types except type PERCENTAGE. PERCENTAGE - rates use the credit type of associated rates. - - custom_rate: Only set for CUSTOM rate_type. This field is interpreted by custom rate - processors. - - ending_before: exclusive end date - - is_prorated: Default proration configuration. Only valid for SUBSCRIPTION rate_type. Must be - set to true. - - price: Default price. For FLAT and SUBSCRIPTION rate_type, this must be >=0. For - PERCENTAGE rate_type, this is a decimal fraction, e.g. use 0.1 for 10%; this - must be >=0 and <=1. - - pricing_group_values: Optional. List of pricing group key value pairs which will be used to calculate - the price. - - quantity: Default quantity. For SUBSCRIPTION rate_type, this must be >=0. - - tiers: Only set for TIERED rate_type. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contract-pricing/rate-cards/addRate", - body=await async_maybe_transform( - { - "entitled": entitled, - "product_id": product_id, - "rate_card_id": rate_card_id, - "rate_type": rate_type, - "starting_at": starting_at, - "billing_frequency": billing_frequency, - "commit_rate": commit_rate, - "credit_type_id": credit_type_id, - "custom_rate": custom_rate, - "ending_before": ending_before, - "is_prorated": is_prorated, - "price": price, - "pricing_group_values": pricing_group_values, - "quantity": quantity, - "tiers": tiers, - }, - rate_add_params.RateAddParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RateAddResponse, - ) - - async def add_many( - self, - *, - rate_card_id: str, - rates: Iterable[rate_add_many_params.Rate], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> RateAddManyResponse: - """ - Add new rates - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contract-pricing/rate-cards/addRates", - body=await async_maybe_transform( - { - "rate_card_id": rate_card_id, - "rates": rates, - }, - rate_add_many_params.RateAddManyParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=RateAddManyResponse, - ) - - -class RatesResourceWithRawResponse: - def __init__(self, rates: RatesResource) -> None: - self._rates = rates - - self.list = to_raw_response_wrapper( - rates.list, - ) - self.add = to_raw_response_wrapper( - rates.add, - ) - self.add_many = to_raw_response_wrapper( - rates.add_many, - ) - - -class AsyncRatesResourceWithRawResponse: - def __init__(self, rates: AsyncRatesResource) -> None: - self._rates = rates - - self.list = async_to_raw_response_wrapper( - rates.list, - ) - self.add = async_to_raw_response_wrapper( - rates.add, - ) - self.add_many = async_to_raw_response_wrapper( - rates.add_many, - ) - - -class RatesResourceWithStreamingResponse: - def __init__(self, rates: RatesResource) -> None: - self._rates = rates - - self.list = to_streamed_response_wrapper( - rates.list, - ) - self.add = to_streamed_response_wrapper( - rates.add, - ) - self.add_many = to_streamed_response_wrapper( - rates.add_many, - ) - - -class AsyncRatesResourceWithStreamingResponse: - def __init__(self, rates: AsyncRatesResource) -> None: - self._rates = rates - - self.list = async_to_streamed_response_wrapper( - rates.list, - ) - self.add = async_to_streamed_response_wrapper( - rates.add, - ) - self.add_many = async_to_streamed_response_wrapper( - rates.add_many, - ) diff --git a/src/metronome/resources/v1/credit_grants.py b/src/metronome/resources/v1/credit_grants.py deleted file mode 100644 index 25ccf4a51..000000000 --- a/src/metronome/resources/v1/credit_grants.py +++ /dev/null @@ -1,874 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union -from datetime import datetime -from typing_extensions import Literal - -import httpx - -from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ...types.v1 import ( - credit_grant_edit_params, - credit_grant_list_params, - credit_grant_void_params, - credit_grant_create_params, - credit_grant_list_entries_params, -) -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ...pagination import SyncCursorPage, AsyncCursorPage, SyncCursorPageWithoutLimit, AsyncCursorPageWithoutLimit -from ..._base_client import AsyncPaginator, make_request_options -from ...types.v1.credit_grant_edit_response import CreditGrantEditResponse -from ...types.v1.credit_grant_list_response import CreditGrantListResponse -from ...types.v1.credit_grant_void_response import CreditGrantVoidResponse -from ...types.v1.credit_grant_create_response import CreditGrantCreateResponse -from ...types.v1.credit_grant_list_entries_response import CreditGrantListEntriesResponse - -__all__ = ["CreditGrantsResource", "AsyncCreditGrantsResource"] - - -class CreditGrantsResource(SyncAPIResource): - """ - [Credit grants](https://docs.metronome.com/invoicing/how-billing-works/manage-credits/) adjust a customer balance for prepayments, reimbursements, promotions, and so on. Use these endpoints to create, retrieve, update, and delete credit grants. - """ - - @cached_property - def with_raw_response(self) -> CreditGrantsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return CreditGrantsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> CreditGrantsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return CreditGrantsResourceWithStreamingResponse(self) - - def create( - self, - *, - customer_id: str, - expires_at: Union[str, datetime], - grant_amount: credit_grant_create_params.GrantAmount, - name: str, - paid_amount: credit_grant_create_params.PaidAmount, - priority: float, - credit_grant_type: str | Omit = omit, - custom_fields: Dict[str, str] | Omit = omit, - effective_at: Union[str, datetime] | Omit = omit, - invoice_date: Union[str, datetime] | Omit = omit, - product_ids: SequenceNotStr[str] | Omit = omit, - reason: str | Omit = omit, - rollover_settings: credit_grant_create_params.RolloverSettings | Omit = omit, - uniqueness_key: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CreditGrantCreateResponse: - """Create a new credit grant. - - This is a Plans (deprecated) endpoint. New clients - should implement using Contracts. - - Args: - customer_id: the Metronome ID of the customer - - expires_at: The credit grant will only apply to usage or charges dated before this timestamp - - grant_amount: the amount of credits granted - - name: the name of the credit grant as it will appear on invoices - - paid_amount: the amount paid for this credit grant - - custom_fields: Custom fields to attach to the credit grant. - - effective_at: The credit grant will only apply to usage or charges dated on or after this - timestamp - - invoice_date: The date to issue an invoice for the paid_amount. - - product_ids: The product(s) which these credits will be applied to. (If unspecified, the - credits will be applied to charges for all products.). The array ordering - specified here will be used to determine the order in which credits will be - applied to invoice line items - - rollover_settings: Configure a rollover for this credit grant so if it expires it rolls over a - configured amount to a new credit grant. This feature is currently opt-in only. - Contact Metronome to be added to the beta. - - uniqueness_key: Prevents the creation of duplicates. If a request to create a record is made - with a previously used uniqueness key, a new record will not be created and the - request will fail with a 409 error. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/credits/createGrant", - body=maybe_transform( - { - "customer_id": customer_id, - "expires_at": expires_at, - "grant_amount": grant_amount, - "name": name, - "paid_amount": paid_amount, - "priority": priority, - "credit_grant_type": credit_grant_type, - "custom_fields": custom_fields, - "effective_at": effective_at, - "invoice_date": invoice_date, - "product_ids": product_ids, - "reason": reason, - "rollover_settings": rollover_settings, - "uniqueness_key": uniqueness_key, - }, - credit_grant_create_params.CreditGrantCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CreditGrantCreateResponse, - ) - - def list( - self, - *, - limit: int | Omit = omit, - next_page: str | Omit = omit, - credit_grant_ids: SequenceNotStr[str] | Omit = omit, - credit_type_ids: SequenceNotStr[str] | Omit = omit, - customer_ids: SequenceNotStr[str] | Omit = omit, - effective_before: Union[str, datetime] | Omit = omit, - not_expiring_before: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[CreditGrantListResponse]: - """List credit grants. - - This list does not included voided grants. This is a Plans - (deprecated) endpoint. New clients should implement using Contracts. - - Args: - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - credit_grant_ids: An array of credit grant IDs. If this is specified, neither credit_type_ids nor - customer_ids may be specified. - - credit_type_ids: An array of credit type IDs. This must not be specified if credit_grant_ids is - specified. - - customer_ids: An array of Metronome customer IDs. This must not be specified if - credit_grant_ids is specified. - - effective_before: Only return credit grants that are effective before this timestamp (exclusive). - - not_expiring_before: Only return credit grants that expire at or after this timestamp. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/credits/listGrants", - page=SyncCursorPage[CreditGrantListResponse], - body=maybe_transform( - { - "credit_grant_ids": credit_grant_ids, - "credit_type_ids": credit_type_ids, - "customer_ids": customer_ids, - "effective_before": effective_before, - "not_expiring_before": not_expiring_before, - }, - credit_grant_list_params.CreditGrantListParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - credit_grant_list_params.CreditGrantListParams, - ), - ), - model=CreditGrantListResponse, - method="post", - ) - - def edit( - self, - *, - id: str, - credit_grant_type: str | Omit = omit, - expires_at: Union[str, datetime] | Omit = omit, - name: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CreditGrantEditResponse: - """Edit an existing credit grant. - - This is a Plans (deprecated) endpoint. New - clients should implement using Contracts. - - Args: - id: the ID of the credit grant - - credit_grant_type: the updated credit grant type - - expires_at: the updated expiration date for the credit grant - - name: the updated name for the credit grant - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/credits/editGrant", - body=maybe_transform( - { - "id": id, - "credit_grant_type": credit_grant_type, - "expires_at": expires_at, - "name": name, - }, - credit_grant_edit_params.CreditGrantEditParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CreditGrantEditResponse, - ) - - def list_entries( - self, - *, - next_page: str | Omit = omit, - sort: Literal["asc", "desc"] | Omit = omit, - credit_type_ids: SequenceNotStr[str] | Omit = omit, - customer_ids: SequenceNotStr[str] | Omit = omit, - ending_before: Union[str, datetime] | Omit = omit, - starting_on: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPageWithoutLimit[CreditGrantListEntriesResponse]: - """Fetches a list of credit ledger entries. - - Returns lists of ledgers per customer. - Ledger entries are returned in chronological order. Ledger entries associated - with voided credit grants are not included. This is a Plans (deprecated) - endpoint. New clients should implement using Contracts. - - Args: - next_page: Cursor that indicates where the next page of results should start. - - sort: Ledgers sort order by date, asc or desc. Defaults to asc. - - credit_type_ids: A list of Metronome credit type IDs to fetch ledger entries for. If absent, - ledger entries for all credit types will be returned. - - customer_ids: A list of Metronome customer IDs to fetch ledger entries for. If absent, ledger - entries for all customers will be returned. - - ending_before: If supplied, ledger entries will only be returned with an effective_at before - this time. This timestamp must not be in the future. If no timestamp is - supplied, all entries up to the start of the customer's next billing period will - be returned. - - starting_on: If supplied, only ledger entries effective at or after this time will be - returned. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/credits/listEntries", - page=SyncCursorPageWithoutLimit[CreditGrantListEntriesResponse], - body=maybe_transform( - { - "credit_type_ids": credit_type_ids, - "customer_ids": customer_ids, - "ending_before": ending_before, - "starting_on": starting_on, - }, - credit_grant_list_entries_params.CreditGrantListEntriesParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "next_page": next_page, - "sort": sort, - }, - credit_grant_list_entries_params.CreditGrantListEntriesParams, - ), - ), - model=CreditGrantListEntriesResponse, - method="post", - ) - - def void( - self, - *, - id: str, - release_uniqueness_key: bool | Omit = omit, - void_credit_purchase_invoice: bool | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CreditGrantVoidResponse: - """Void a credit grant. - - This is a Plans (deprecated) endpoint. New clients should - implement using Contracts. - - Args: - release_uniqueness_key: If true, resets the uniqueness key on this grant so it can be re-used - - void_credit_purchase_invoice: If true, void the purchase invoice associated with the grant - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/credits/voidGrant", - body=maybe_transform( - { - "id": id, - "release_uniqueness_key": release_uniqueness_key, - "void_credit_purchase_invoice": void_credit_purchase_invoice, - }, - credit_grant_void_params.CreditGrantVoidParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CreditGrantVoidResponse, - ) - - -class AsyncCreditGrantsResource(AsyncAPIResource): - """ - [Credit grants](https://docs.metronome.com/invoicing/how-billing-works/manage-credits/) adjust a customer balance for prepayments, reimbursements, promotions, and so on. Use these endpoints to create, retrieve, update, and delete credit grants. - """ - - @cached_property - def with_raw_response(self) -> AsyncCreditGrantsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncCreditGrantsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncCreditGrantsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncCreditGrantsResourceWithStreamingResponse(self) - - async def create( - self, - *, - customer_id: str, - expires_at: Union[str, datetime], - grant_amount: credit_grant_create_params.GrantAmount, - name: str, - paid_amount: credit_grant_create_params.PaidAmount, - priority: float, - credit_grant_type: str | Omit = omit, - custom_fields: Dict[str, str] | Omit = omit, - effective_at: Union[str, datetime] | Omit = omit, - invoice_date: Union[str, datetime] | Omit = omit, - product_ids: SequenceNotStr[str] | Omit = omit, - reason: str | Omit = omit, - rollover_settings: credit_grant_create_params.RolloverSettings | Omit = omit, - uniqueness_key: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CreditGrantCreateResponse: - """Create a new credit grant. - - This is a Plans (deprecated) endpoint. New clients - should implement using Contracts. - - Args: - customer_id: the Metronome ID of the customer - - expires_at: The credit grant will only apply to usage or charges dated before this timestamp - - grant_amount: the amount of credits granted - - name: the name of the credit grant as it will appear on invoices - - paid_amount: the amount paid for this credit grant - - custom_fields: Custom fields to attach to the credit grant. - - effective_at: The credit grant will only apply to usage or charges dated on or after this - timestamp - - invoice_date: The date to issue an invoice for the paid_amount. - - product_ids: The product(s) which these credits will be applied to. (If unspecified, the - credits will be applied to charges for all products.). The array ordering - specified here will be used to determine the order in which credits will be - applied to invoice line items - - rollover_settings: Configure a rollover for this credit grant so if it expires it rolls over a - configured amount to a new credit grant. This feature is currently opt-in only. - Contact Metronome to be added to the beta. - - uniqueness_key: Prevents the creation of duplicates. If a request to create a record is made - with a previously used uniqueness key, a new record will not be created and the - request will fail with a 409 error. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/credits/createGrant", - body=await async_maybe_transform( - { - "customer_id": customer_id, - "expires_at": expires_at, - "grant_amount": grant_amount, - "name": name, - "paid_amount": paid_amount, - "priority": priority, - "credit_grant_type": credit_grant_type, - "custom_fields": custom_fields, - "effective_at": effective_at, - "invoice_date": invoice_date, - "product_ids": product_ids, - "reason": reason, - "rollover_settings": rollover_settings, - "uniqueness_key": uniqueness_key, - }, - credit_grant_create_params.CreditGrantCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CreditGrantCreateResponse, - ) - - def list( - self, - *, - limit: int | Omit = omit, - next_page: str | Omit = omit, - credit_grant_ids: SequenceNotStr[str] | Omit = omit, - credit_type_ids: SequenceNotStr[str] | Omit = omit, - customer_ids: SequenceNotStr[str] | Omit = omit, - effective_before: Union[str, datetime] | Omit = omit, - not_expiring_before: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[CreditGrantListResponse, AsyncCursorPage[CreditGrantListResponse]]: - """List credit grants. - - This list does not included voided grants. This is a Plans - (deprecated) endpoint. New clients should implement using Contracts. - - Args: - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - credit_grant_ids: An array of credit grant IDs. If this is specified, neither credit_type_ids nor - customer_ids may be specified. - - credit_type_ids: An array of credit type IDs. This must not be specified if credit_grant_ids is - specified. - - customer_ids: An array of Metronome customer IDs. This must not be specified if - credit_grant_ids is specified. - - effective_before: Only return credit grants that are effective before this timestamp (exclusive). - - not_expiring_before: Only return credit grants that expire at or after this timestamp. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/credits/listGrants", - page=AsyncCursorPage[CreditGrantListResponse], - body=maybe_transform( - { - "credit_grant_ids": credit_grant_ids, - "credit_type_ids": credit_type_ids, - "customer_ids": customer_ids, - "effective_before": effective_before, - "not_expiring_before": not_expiring_before, - }, - credit_grant_list_params.CreditGrantListParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - credit_grant_list_params.CreditGrantListParams, - ), - ), - model=CreditGrantListResponse, - method="post", - ) - - async def edit( - self, - *, - id: str, - credit_grant_type: str | Omit = omit, - expires_at: Union[str, datetime] | Omit = omit, - name: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CreditGrantEditResponse: - """Edit an existing credit grant. - - This is a Plans (deprecated) endpoint. New - clients should implement using Contracts. - - Args: - id: the ID of the credit grant - - credit_grant_type: the updated credit grant type - - expires_at: the updated expiration date for the credit grant - - name: the updated name for the credit grant - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/credits/editGrant", - body=await async_maybe_transform( - { - "id": id, - "credit_grant_type": credit_grant_type, - "expires_at": expires_at, - "name": name, - }, - credit_grant_edit_params.CreditGrantEditParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CreditGrantEditResponse, - ) - - def list_entries( - self, - *, - next_page: str | Omit = omit, - sort: Literal["asc", "desc"] | Omit = omit, - credit_type_ids: SequenceNotStr[str] | Omit = omit, - customer_ids: SequenceNotStr[str] | Omit = omit, - ending_before: Union[str, datetime] | Omit = omit, - starting_on: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[CreditGrantListEntriesResponse, AsyncCursorPageWithoutLimit[CreditGrantListEntriesResponse]]: - """Fetches a list of credit ledger entries. - - Returns lists of ledgers per customer. - Ledger entries are returned in chronological order. Ledger entries associated - with voided credit grants are not included. This is a Plans (deprecated) - endpoint. New clients should implement using Contracts. - - Args: - next_page: Cursor that indicates where the next page of results should start. - - sort: Ledgers sort order by date, asc or desc. Defaults to asc. - - credit_type_ids: A list of Metronome credit type IDs to fetch ledger entries for. If absent, - ledger entries for all credit types will be returned. - - customer_ids: A list of Metronome customer IDs to fetch ledger entries for. If absent, ledger - entries for all customers will be returned. - - ending_before: If supplied, ledger entries will only be returned with an effective_at before - this time. This timestamp must not be in the future. If no timestamp is - supplied, all entries up to the start of the customer's next billing period will - be returned. - - starting_on: If supplied, only ledger entries effective at or after this time will be - returned. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/credits/listEntries", - page=AsyncCursorPageWithoutLimit[CreditGrantListEntriesResponse], - body=maybe_transform( - { - "credit_type_ids": credit_type_ids, - "customer_ids": customer_ids, - "ending_before": ending_before, - "starting_on": starting_on, - }, - credit_grant_list_entries_params.CreditGrantListEntriesParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "next_page": next_page, - "sort": sort, - }, - credit_grant_list_entries_params.CreditGrantListEntriesParams, - ), - ), - model=CreditGrantListEntriesResponse, - method="post", - ) - - async def void( - self, - *, - id: str, - release_uniqueness_key: bool | Omit = omit, - void_credit_purchase_invoice: bool | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CreditGrantVoidResponse: - """Void a credit grant. - - This is a Plans (deprecated) endpoint. New clients should - implement using Contracts. - - Args: - release_uniqueness_key: If true, resets the uniqueness key on this grant so it can be re-used - - void_credit_purchase_invoice: If true, void the purchase invoice associated with the grant - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/credits/voidGrant", - body=await async_maybe_transform( - { - "id": id, - "release_uniqueness_key": release_uniqueness_key, - "void_credit_purchase_invoice": void_credit_purchase_invoice, - }, - credit_grant_void_params.CreditGrantVoidParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CreditGrantVoidResponse, - ) - - -class CreditGrantsResourceWithRawResponse: - def __init__(self, credit_grants: CreditGrantsResource) -> None: - self._credit_grants = credit_grants - - self.create = to_raw_response_wrapper( - credit_grants.create, - ) - self.list = to_raw_response_wrapper( - credit_grants.list, - ) - self.edit = to_raw_response_wrapper( - credit_grants.edit, - ) - self.list_entries = to_raw_response_wrapper( - credit_grants.list_entries, - ) - self.void = to_raw_response_wrapper( - credit_grants.void, - ) - - -class AsyncCreditGrantsResourceWithRawResponse: - def __init__(self, credit_grants: AsyncCreditGrantsResource) -> None: - self._credit_grants = credit_grants - - self.create = async_to_raw_response_wrapper( - credit_grants.create, - ) - self.list = async_to_raw_response_wrapper( - credit_grants.list, - ) - self.edit = async_to_raw_response_wrapper( - credit_grants.edit, - ) - self.list_entries = async_to_raw_response_wrapper( - credit_grants.list_entries, - ) - self.void = async_to_raw_response_wrapper( - credit_grants.void, - ) - - -class CreditGrantsResourceWithStreamingResponse: - def __init__(self, credit_grants: CreditGrantsResource) -> None: - self._credit_grants = credit_grants - - self.create = to_streamed_response_wrapper( - credit_grants.create, - ) - self.list = to_streamed_response_wrapper( - credit_grants.list, - ) - self.edit = to_streamed_response_wrapper( - credit_grants.edit, - ) - self.list_entries = to_streamed_response_wrapper( - credit_grants.list_entries, - ) - self.void = to_streamed_response_wrapper( - credit_grants.void, - ) - - -class AsyncCreditGrantsResourceWithStreamingResponse: - def __init__(self, credit_grants: AsyncCreditGrantsResource) -> None: - self._credit_grants = credit_grants - - self.create = async_to_streamed_response_wrapper( - credit_grants.create, - ) - self.list = async_to_streamed_response_wrapper( - credit_grants.list, - ) - self.edit = async_to_streamed_response_wrapper( - credit_grants.edit, - ) - self.list_entries = async_to_streamed_response_wrapper( - credit_grants.list_entries, - ) - self.void = async_to_streamed_response_wrapper( - credit_grants.void, - ) diff --git a/src/metronome/resources/v1/custom_fields.py b/src/metronome/resources/v1/custom_fields.py deleted file mode 100644 index be40ec11a..000000000 --- a/src/metronome/resources/v1/custom_fields.py +++ /dev/null @@ -1,911 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, List -from typing_extensions import Literal - -import httpx - -from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ...types.v1 import ( - custom_field_add_key_params, - custom_field_list_keys_params, - custom_field_remove_key_params, - custom_field_set_values_params, - custom_field_delete_values_params, -) -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ...pagination import SyncCursorPageWithoutLimit, AsyncCursorPageWithoutLimit -from ..._base_client import AsyncPaginator, make_request_options -from ...types.v1.custom_field_list_keys_response import CustomFieldListKeysResponse - -__all__ = ["CustomFieldsResource", "AsyncCustomFieldsResource"] - - -class CustomFieldsResource(SyncAPIResource): - """ - [Custom fields](https://docs.metronome.com/integrations/custom-fields/) enable adding additional data to Metronome entities. Use these endpoints to create, retrieve, update, and delete custom fields. - """ - - @cached_property - def with_raw_response(self) -> CustomFieldsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return CustomFieldsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> CustomFieldsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return CustomFieldsResourceWithStreamingResponse(self) - - def add_key( - self, - *, - enforce_uniqueness: bool, - entity: Literal[ - "alert", - "billable_metric", - "charge", - "commit", - "contract_credit", - "contract_product", - "contract", - "credit_grant", - "customer_plan", - "customer", - "discount", - "invoice", - "plan", - "professional_service", - "product", - "rate_card", - "scheduled_charge", - "subscription", - "package_commit", - "package_credit", - "package_subscription", - "package_scheduled_charge", - ], - key: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """Creates a new custom field key for a given entity (e.g. - - billable metric, - contract, alert). - - Custom fields are properties that you can add to Metronome objects to store - metadata like foreign keys or other descriptors. This metadata can get - transferred to or accessed by other systems to contextualize Metronome data and - power business processes. For example, to service workflows like revenue - recognition, reconciliation, and invoicing, custom fields help Metronome know - the relationship between entities in the platform and third-party systems. - - ### Use this endpoint to: - - - Create a new custom field key for Customer objects in Metronome. You can then - use the Set Custom Field Values endpoint to set the value of this key for a - specific customer. - - Specify whether the key should enforce uniqueness. If the key is set to - enforce uniqueness and you attempt to set a custom field value for the key - that already exists, it will fail. - - ### Usage guidelines: - - - Custom fields set on commits, credits, and contracts can be used to scope - alert evaluation. For example, you can create a spend threshold alert that - only considers spend associated with contracts with custom field key - `contract_type` and value `paygo` - - Custom fields set on products can be used in the Stripe integration to set - metadata on invoices. - - Custom fields for customers, contracts, invoices, products, commits, scheduled - charges, and subscriptions are passed down to the invoice. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._post( - "/v1/customFields/addKey", - body=maybe_transform( - { - "enforce_uniqueness": enforce_uniqueness, - "entity": entity, - "key": key, - }, - custom_field_add_key_params.CustomFieldAddKeyParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def delete_values( - self, - *, - entity: Literal[ - "alert", - "billable_metric", - "charge", - "commit", - "contract_credit", - "contract_product", - "contract", - "credit_grant", - "customer_plan", - "customer", - "discount", - "invoice", - "plan", - "professional_service", - "product", - "rate_card", - "scheduled_charge", - "subscription", - "package_commit", - "package_credit", - "package_subscription", - "package_scheduled_charge", - ], - entity_id: str, - keys: SequenceNotStr[str], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - Remove specific custom field values from a Metronome entity instance by - specifying the field keys to delete. Use this endpoint to clean up unwanted - custom field data while preserving other fields on the same entity. Requires the - entity type, entity ID, and array of keys to remove. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._post( - "/v1/customFields/deleteValues", - body=maybe_transform( - { - "entity": entity, - "entity_id": entity_id, - "keys": keys, - }, - custom_field_delete_values_params.CustomFieldDeleteValuesParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def list_keys( - self, - *, - next_page: str | Omit = omit, - entities: List[ - Literal[ - "alert", - "billable_metric", - "charge", - "commit", - "contract_credit", - "contract_product", - "contract", - "credit_grant", - "customer_plan", - "customer", - "discount", - "invoice", - "plan", - "professional_service", - "product", - "rate_card", - "scheduled_charge", - "subscription", - "package_commit", - "package_credit", - "package_subscription", - "package_scheduled_charge", - ] - ] - | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPageWithoutLimit[CustomFieldListKeysResponse]: - """ - Retrieve all your active custom field keys, with optional filtering by entity - type (customer, contract, product, etc.). Use this endpoint to discover what - custom field keys are available before setting values on entities or to audit - your custom field configuration across different entity types. - - Args: - next_page: Cursor that indicates where the next page of results should start. - - entities: Optional list of entity types to return keys for - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/customFields/listKeys", - page=SyncCursorPageWithoutLimit[CustomFieldListKeysResponse], - body=maybe_transform({"entities": entities}, custom_field_list_keys_params.CustomFieldListKeysParams), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - {"next_page": next_page}, custom_field_list_keys_params.CustomFieldListKeysParams - ), - ), - model=CustomFieldListKeysResponse, - method="post", - ) - - def remove_key( - self, - *, - entity: Literal[ - "alert", - "billable_metric", - "charge", - "commit", - "contract_credit", - "contract_product", - "contract", - "credit_grant", - "customer_plan", - "customer", - "discount", - "invoice", - "plan", - "professional_service", - "product", - "rate_card", - "scheduled_charge", - "subscription", - "package_commit", - "package_credit", - "package_subscription", - "package_scheduled_charge", - ], - key: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - Removes a custom field key from the allowlist for a specific entity type, - preventing future use of that key across all instances of the entity. Existing - values for this key on entity instances will no longer be accessible once the - key is removed. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._post( - "/v1/customFields/removeKey", - body=maybe_transform( - { - "entity": entity, - "key": key, - }, - custom_field_remove_key_params.CustomFieldRemoveKeyParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def set_values( - self, - *, - custom_fields: Dict[str, str], - entity: Literal[ - "alert", - "billable_metric", - "charge", - "commit", - "contract_credit", - "contract_product", - "contract", - "credit_grant", - "customer_plan", - "customer", - "discount", - "invoice", - "plan", - "professional_service", - "product", - "rate_card", - "scheduled_charge", - "subscription", - "package_commit", - "package_credit", - "package_subscription", - "package_scheduled_charge", - ], - entity_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """Sets custom field values on a specific Metronome entity instance. - - Overwrites - existing values for matching keys while preserving other fields. All updates are - transactional—either all values are set or none are. Custom field values are - limited to 200 characters each. - - Args: - custom_fields: Custom fields to be added eg. { "key1": "value1", "key2": "value2" } - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._post( - "/v1/customFields/setValues", - body=maybe_transform( - { - "custom_fields": custom_fields, - "entity": entity, - "entity_id": entity_id, - }, - custom_field_set_values_params.CustomFieldSetValuesParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class AsyncCustomFieldsResource(AsyncAPIResource): - """ - [Custom fields](https://docs.metronome.com/integrations/custom-fields/) enable adding additional data to Metronome entities. Use these endpoints to create, retrieve, update, and delete custom fields. - """ - - @cached_property - def with_raw_response(self) -> AsyncCustomFieldsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncCustomFieldsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncCustomFieldsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncCustomFieldsResourceWithStreamingResponse(self) - - async def add_key( - self, - *, - enforce_uniqueness: bool, - entity: Literal[ - "alert", - "billable_metric", - "charge", - "commit", - "contract_credit", - "contract_product", - "contract", - "credit_grant", - "customer_plan", - "customer", - "discount", - "invoice", - "plan", - "professional_service", - "product", - "rate_card", - "scheduled_charge", - "subscription", - "package_commit", - "package_credit", - "package_subscription", - "package_scheduled_charge", - ], - key: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """Creates a new custom field key for a given entity (e.g. - - billable metric, - contract, alert). - - Custom fields are properties that you can add to Metronome objects to store - metadata like foreign keys or other descriptors. This metadata can get - transferred to or accessed by other systems to contextualize Metronome data and - power business processes. For example, to service workflows like revenue - recognition, reconciliation, and invoicing, custom fields help Metronome know - the relationship between entities in the platform and third-party systems. - - ### Use this endpoint to: - - - Create a new custom field key for Customer objects in Metronome. You can then - use the Set Custom Field Values endpoint to set the value of this key for a - specific customer. - - Specify whether the key should enforce uniqueness. If the key is set to - enforce uniqueness and you attempt to set a custom field value for the key - that already exists, it will fail. - - ### Usage guidelines: - - - Custom fields set on commits, credits, and contracts can be used to scope - alert evaluation. For example, you can create a spend threshold alert that - only considers spend associated with contracts with custom field key - `contract_type` and value `paygo` - - Custom fields set on products can be used in the Stripe integration to set - metadata on invoices. - - Custom fields for customers, contracts, invoices, products, commits, scheduled - charges, and subscriptions are passed down to the invoice. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._post( - "/v1/customFields/addKey", - body=await async_maybe_transform( - { - "enforce_uniqueness": enforce_uniqueness, - "entity": entity, - "key": key, - }, - custom_field_add_key_params.CustomFieldAddKeyParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - async def delete_values( - self, - *, - entity: Literal[ - "alert", - "billable_metric", - "charge", - "commit", - "contract_credit", - "contract_product", - "contract", - "credit_grant", - "customer_plan", - "customer", - "discount", - "invoice", - "plan", - "professional_service", - "product", - "rate_card", - "scheduled_charge", - "subscription", - "package_commit", - "package_credit", - "package_subscription", - "package_scheduled_charge", - ], - entity_id: str, - keys: SequenceNotStr[str], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - Remove specific custom field values from a Metronome entity instance by - specifying the field keys to delete. Use this endpoint to clean up unwanted - custom field data while preserving other fields on the same entity. Requires the - entity type, entity ID, and array of keys to remove. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._post( - "/v1/customFields/deleteValues", - body=await async_maybe_transform( - { - "entity": entity, - "entity_id": entity_id, - "keys": keys, - }, - custom_field_delete_values_params.CustomFieldDeleteValuesParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def list_keys( - self, - *, - next_page: str | Omit = omit, - entities: List[ - Literal[ - "alert", - "billable_metric", - "charge", - "commit", - "contract_credit", - "contract_product", - "contract", - "credit_grant", - "customer_plan", - "customer", - "discount", - "invoice", - "plan", - "professional_service", - "product", - "rate_card", - "scheduled_charge", - "subscription", - "package_commit", - "package_credit", - "package_subscription", - "package_scheduled_charge", - ] - ] - | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[CustomFieldListKeysResponse, AsyncCursorPageWithoutLimit[CustomFieldListKeysResponse]]: - """ - Retrieve all your active custom field keys, with optional filtering by entity - type (customer, contract, product, etc.). Use this endpoint to discover what - custom field keys are available before setting values on entities or to audit - your custom field configuration across different entity types. - - Args: - next_page: Cursor that indicates where the next page of results should start. - - entities: Optional list of entity types to return keys for - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/customFields/listKeys", - page=AsyncCursorPageWithoutLimit[CustomFieldListKeysResponse], - body=maybe_transform({"entities": entities}, custom_field_list_keys_params.CustomFieldListKeysParams), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - {"next_page": next_page}, custom_field_list_keys_params.CustomFieldListKeysParams - ), - ), - model=CustomFieldListKeysResponse, - method="post", - ) - - async def remove_key( - self, - *, - entity: Literal[ - "alert", - "billable_metric", - "charge", - "commit", - "contract_credit", - "contract_product", - "contract", - "credit_grant", - "customer_plan", - "customer", - "discount", - "invoice", - "plan", - "professional_service", - "product", - "rate_card", - "scheduled_charge", - "subscription", - "package_commit", - "package_credit", - "package_subscription", - "package_scheduled_charge", - ], - key: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - Removes a custom field key from the allowlist for a specific entity type, - preventing future use of that key across all instances of the entity. Existing - values for this key on entity instances will no longer be accessible once the - key is removed. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._post( - "/v1/customFields/removeKey", - body=await async_maybe_transform( - { - "entity": entity, - "key": key, - }, - custom_field_remove_key_params.CustomFieldRemoveKeyParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - async def set_values( - self, - *, - custom_fields: Dict[str, str], - entity: Literal[ - "alert", - "billable_metric", - "charge", - "commit", - "contract_credit", - "contract_product", - "contract", - "credit_grant", - "customer_plan", - "customer", - "discount", - "invoice", - "plan", - "professional_service", - "product", - "rate_card", - "scheduled_charge", - "subscription", - "package_commit", - "package_credit", - "package_subscription", - "package_scheduled_charge", - ], - entity_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """Sets custom field values on a specific Metronome entity instance. - - Overwrites - existing values for matching keys while preserving other fields. All updates are - transactional—either all values are set or none are. Custom field values are - limited to 200 characters each. - - Args: - custom_fields: Custom fields to be added eg. { "key1": "value1", "key2": "value2" } - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._post( - "/v1/customFields/setValues", - body=await async_maybe_transform( - { - "custom_fields": custom_fields, - "entity": entity, - "entity_id": entity_id, - }, - custom_field_set_values_params.CustomFieldSetValuesParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class CustomFieldsResourceWithRawResponse: - def __init__(self, custom_fields: CustomFieldsResource) -> None: - self._custom_fields = custom_fields - - self.add_key = to_raw_response_wrapper( - custom_fields.add_key, - ) - self.delete_values = to_raw_response_wrapper( - custom_fields.delete_values, - ) - self.list_keys = to_raw_response_wrapper( - custom_fields.list_keys, - ) - self.remove_key = to_raw_response_wrapper( - custom_fields.remove_key, - ) - self.set_values = to_raw_response_wrapper( - custom_fields.set_values, - ) - - -class AsyncCustomFieldsResourceWithRawResponse: - def __init__(self, custom_fields: AsyncCustomFieldsResource) -> None: - self._custom_fields = custom_fields - - self.add_key = async_to_raw_response_wrapper( - custom_fields.add_key, - ) - self.delete_values = async_to_raw_response_wrapper( - custom_fields.delete_values, - ) - self.list_keys = async_to_raw_response_wrapper( - custom_fields.list_keys, - ) - self.remove_key = async_to_raw_response_wrapper( - custom_fields.remove_key, - ) - self.set_values = async_to_raw_response_wrapper( - custom_fields.set_values, - ) - - -class CustomFieldsResourceWithStreamingResponse: - def __init__(self, custom_fields: CustomFieldsResource) -> None: - self._custom_fields = custom_fields - - self.add_key = to_streamed_response_wrapper( - custom_fields.add_key, - ) - self.delete_values = to_streamed_response_wrapper( - custom_fields.delete_values, - ) - self.list_keys = to_streamed_response_wrapper( - custom_fields.list_keys, - ) - self.remove_key = to_streamed_response_wrapper( - custom_fields.remove_key, - ) - self.set_values = to_streamed_response_wrapper( - custom_fields.set_values, - ) - - -class AsyncCustomFieldsResourceWithStreamingResponse: - def __init__(self, custom_fields: AsyncCustomFieldsResource) -> None: - self._custom_fields = custom_fields - - self.add_key = async_to_streamed_response_wrapper( - custom_fields.add_key, - ) - self.delete_values = async_to_streamed_response_wrapper( - custom_fields.delete_values, - ) - self.list_keys = async_to_streamed_response_wrapper( - custom_fields.list_keys, - ) - self.remove_key = async_to_streamed_response_wrapper( - custom_fields.remove_key, - ) - self.set_values = async_to_streamed_response_wrapper( - custom_fields.set_values, - ) diff --git a/src/metronome/resources/v1/customers/__init__.py b/src/metronome/resources/v1/customers/__init__.py deleted file mode 100644 index d34c8b020..000000000 --- a/src/metronome/resources/v1/customers/__init__.py +++ /dev/null @@ -1,117 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .plans import ( - PlansResource, - AsyncPlansResource, - PlansResourceWithRawResponse, - AsyncPlansResourceWithRawResponse, - PlansResourceWithStreamingResponse, - AsyncPlansResourceWithStreamingResponse, -) -from .alerts import ( - AlertsResource, - AsyncAlertsResource, - AlertsResourceWithRawResponse, - AsyncAlertsResourceWithRawResponse, - AlertsResourceWithStreamingResponse, - AsyncAlertsResourceWithStreamingResponse, -) -from .commits import ( - CommitsResource, - AsyncCommitsResource, - CommitsResourceWithRawResponse, - AsyncCommitsResourceWithRawResponse, - CommitsResourceWithStreamingResponse, - AsyncCommitsResourceWithStreamingResponse, -) -from .credits import ( - CreditsResource, - AsyncCreditsResource, - CreditsResourceWithRawResponse, - AsyncCreditsResourceWithRawResponse, - CreditsResourceWithStreamingResponse, - AsyncCreditsResourceWithStreamingResponse, -) -from .invoices import ( - InvoicesResource, - AsyncInvoicesResource, - InvoicesResourceWithRawResponse, - AsyncInvoicesResourceWithRawResponse, - InvoicesResourceWithStreamingResponse, - AsyncInvoicesResourceWithStreamingResponse, -) -from .customers import ( - CustomersResource, - AsyncCustomersResource, - CustomersResourceWithRawResponse, - AsyncCustomersResourceWithRawResponse, - CustomersResourceWithStreamingResponse, - AsyncCustomersResourceWithStreamingResponse, -) -from .billing_config import ( - BillingConfigResource, - AsyncBillingConfigResource, - BillingConfigResourceWithRawResponse, - AsyncBillingConfigResourceWithRawResponse, - BillingConfigResourceWithStreamingResponse, - AsyncBillingConfigResourceWithStreamingResponse, -) -from .named_schedules import ( - NamedSchedulesResource, - AsyncNamedSchedulesResource, - NamedSchedulesResourceWithRawResponse, - AsyncNamedSchedulesResourceWithRawResponse, - NamedSchedulesResourceWithStreamingResponse, - AsyncNamedSchedulesResourceWithStreamingResponse, -) - -__all__ = [ - "AlertsResource", - "AsyncAlertsResource", - "AlertsResourceWithRawResponse", - "AsyncAlertsResourceWithRawResponse", - "AlertsResourceWithStreamingResponse", - "AsyncAlertsResourceWithStreamingResponse", - "PlansResource", - "AsyncPlansResource", - "PlansResourceWithRawResponse", - "AsyncPlansResourceWithRawResponse", - "PlansResourceWithStreamingResponse", - "AsyncPlansResourceWithStreamingResponse", - "InvoicesResource", - "AsyncInvoicesResource", - "InvoicesResourceWithRawResponse", - "AsyncInvoicesResourceWithRawResponse", - "InvoicesResourceWithStreamingResponse", - "AsyncInvoicesResourceWithStreamingResponse", - "BillingConfigResource", - "AsyncBillingConfigResource", - "BillingConfigResourceWithRawResponse", - "AsyncBillingConfigResourceWithRawResponse", - "BillingConfigResourceWithStreamingResponse", - "AsyncBillingConfigResourceWithStreamingResponse", - "CommitsResource", - "AsyncCommitsResource", - "CommitsResourceWithRawResponse", - "AsyncCommitsResourceWithRawResponse", - "CommitsResourceWithStreamingResponse", - "AsyncCommitsResourceWithStreamingResponse", - "CreditsResource", - "AsyncCreditsResource", - "CreditsResourceWithRawResponse", - "AsyncCreditsResourceWithRawResponse", - "CreditsResourceWithStreamingResponse", - "AsyncCreditsResourceWithStreamingResponse", - "NamedSchedulesResource", - "AsyncNamedSchedulesResource", - "NamedSchedulesResourceWithRawResponse", - "AsyncNamedSchedulesResourceWithRawResponse", - "NamedSchedulesResourceWithStreamingResponse", - "AsyncNamedSchedulesResourceWithStreamingResponse", - "CustomersResource", - "AsyncCustomersResource", - "CustomersResourceWithRawResponse", - "AsyncCustomersResourceWithRawResponse", - "CustomersResourceWithStreamingResponse", - "AsyncCustomersResourceWithStreamingResponse", -] diff --git a/src/metronome/resources/v1/customers/alerts.py b/src/metronome/resources/v1/customers/alerts.py deleted file mode 100644 index a62d508e6..000000000 --- a/src/metronome/resources/v1/customers/alerts.py +++ /dev/null @@ -1,670 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List, Iterable -from typing_extensions import Literal - -import httpx - -from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ....pagination import SyncCursorPageWithoutLimit, AsyncCursorPageWithoutLimit -from ...._base_client import AsyncPaginator, make_request_options -from ....types.v1.customers import alert_list_params, alert_reset_params, alert_retrieve_params -from ....types.v1.customers.customer_alert import CustomerAlert -from ....types.v1.customers.alert_retrieve_response import AlertRetrieveResponse - -__all__ = ["AlertsResource", "AsyncAlertsResource"] - - -class AlertsResource(SyncAPIResource): - """ - [Alerts](https://docs.metronome.com/connecting-metronome/alerts/) monitor customer spending, balances, and other billing factors. Use these endpoints to create, retrieve, and archive customer alerts. To view sample alert payloads by alert type, navigate [here.](https://docs.metronome.com/manage-product-access/create-manage-alerts/#webhook-notifications) - """ - - @cached_property - def with_raw_response(self) -> AlertsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AlertsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AlertsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AlertsResourceWithStreamingResponse(self) - - def retrieve( - self, - *, - alert_id: str, - customer_id: str, - group_values: Iterable[alert_retrieve_params.GroupValue] | Omit = omit, - plans_or_contracts: Literal["PLANS", "CONTRACTS"] | Omit = omit, - seat_filter: alert_retrieve_params.SeatFilter | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AlertRetrieveResponse: - """ - Retrieve the real-time evaluation status for a specific threshold - notification-customer pair. This endpoint provides instant visibility into - whether a customer has triggered a threshold notification condition, enabling - you to monitor account health and take proactive action based on current - threshold notification states. - - ### Use this endpoint to: - - - Check if a specific customer is currently violating an threshold notification - (`in_alarm` status) - - Verify threshold notification configuration details and threshold values for a - customer - - Monitor the evaluation state of newly created or recently modified threshold - notification - - Build dashboards or automated workflows that respond to specific threshold - notification conditions - - Validate threshold notification behavior before deploying to production - customers - - Integrate threshold notification status checks into customer support tools or - admin interfaces - - ### Key response fields: - - A CustomerAlert object containing: - - - `customer_status`: The current evaluation state - - - `ok` - Customer is within acceptable thresholds - - `in_alarm` - Customer has breached the threshold for the notification - - `evaluating` - Notification is currently being evaluated (typically during - initial setup) - - `null` - Notification has been archived - - `triggered_by`: Additional context about what caused the notification to - trigger (when applicable) - - alert: Complete threshold notification configuration including: - - Notification ID, name, and type - - Current threshold values and credit type information - - Notification status (enabled, disabled, or archived) - - Last update timestamp - - Any applied filters (credit grant types, custom fields, group values) - - ### Usage guidelines: - - - Customer status: Returns the current evaluation state, not historical data. - For threshold notification history, use webhook notifications or event logs - - Required parameters: Both customer_id and alert_id must be valid UUIDs that - exist in your organization - - Archived notifications: Returns null for customer_status if the notification - has been archived, but still includes the notification configuration details - - Performance considerations: This endpoint queries live evaluation state, - making it ideal for real-time monitoring but not for bulk status checks - - Integration patterns: Best used for on-demand status checks in response to - user actions or as part of targeted monitoring workflows - - Error handling: Returns 404 if either the customer or alert_id doesn't exist - or isn't accessible to your organization - - Args: - alert_id: The Metronome ID of the threshold notification - - customer_id: The Metronome ID of the customer - - group_values: Only present for `spend_threshold_reached` notifications. Retrieve the - notification for a specific group key-value pair. - - plans_or_contracts: When parallel threshold notifications are enabled during migration, this flag - denotes whether to fetch notifications for plans or contracts. - - seat_filter: Only allowed for `low_remaining_seat_balance_reached` notifications. This - filters alerts by the seat group key-value pair. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/customer-alerts/get", - body=maybe_transform( - { - "alert_id": alert_id, - "customer_id": customer_id, - "group_values": group_values, - "plans_or_contracts": plans_or_contracts, - "seat_filter": seat_filter, - }, - alert_retrieve_params.AlertRetrieveParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=AlertRetrieveResponse, - ) - - def list( - self, - *, - customer_id: str, - next_page: str | Omit = omit, - alert_statuses: List[Literal["ENABLED", "DISABLED", "ARCHIVED"]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPageWithoutLimit[CustomerAlert]: - """ - Retrieve all threshold notification configurations and their current statuses - for a specific customer in a single API call. This endpoint provides a - comprehensive view of all threshold notification monitoring a customer account. - - ### Use this endpoint to: - - - Display all active threshold notifications for a customer in dashboards or - admin panels - - Quickly identify which threshold notifications a customer is currently - triggering - - Audit threshold notification coverage for specific accounts - - Filter threshold notifications by status (enabled, disabled, or archived) - - ### Key response fields: - - - data: Array of CustomerAlert objects, each containing: - - Current evaluation status (`ok`, `in_alarm`, `evaluating`, or `null`) - - Complete threshold notification configuration and threshold details - - Threshold notification metadata including type, name, and last update time - - next_page: Pagination cursor for retrieving additional results - - ### Usage guidelines: - - - Default behavior: Returns only enabled threshold notifications unless - `alert_statuses` filter is specified - - Pagination: Use the `next_page` cursor to retrieve all results for customers - with many notifications - - Performance: Efficiently retrieves multiple threshold notification statuses in - a single request instead of making individual calls - - Filtering: Pass the `alert_statuses` array to include disabled or archived - threshold notifications in results - - Args: - customer_id: The Metronome ID of the customer - - next_page: Cursor that indicates where the next page of results should start. - - alert_statuses: Optionally filter by threshold notification status. If absent, only enabled - notifications will be returned. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/customer-alerts/list", - page=SyncCursorPageWithoutLimit[CustomerAlert], - body=maybe_transform( - { - "customer_id": customer_id, - "alert_statuses": alert_statuses, - }, - alert_list_params.AlertListParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"next_page": next_page}, alert_list_params.AlertListParams), - ), - model=CustomerAlert, - method="post", - ) - - def reset( - self, - *, - alert_id: str, - customer_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - Force an immediate re-evaluation of a specific threshold notification for a - customer, clearing any previous state and triggering a fresh assessment against - current thresholds. This endpoint ensures threshold notification accuracy after - configuration changes or data corrections. - - ### Use this endpoint to: - - - Clear false positive threshold notifications after fixing data issues - - Re-evaluate threshold notifications after adjusting customer balances or - credits - - Test threshold notification behavior during development and debugging - - Resolve stuck threshold notification that may be in an incorrect state - - Trigger immediate evaluation after threshold modifications - - ### Key response fields: - - - 200 Success: Confirmation that the threshold notification has been reset and - re-evaluation initiated - - No response body is returned - the operation completes asynchronously - - ### Usage guidelines: - - - Immediate effect: Triggers re-evaluation instantly, which may result in new - webhook notifications if thresholds are breached - - State clearing: Removes any cached evaluation state, ensuring a fresh - assessment - - Use sparingly: Intended for exceptional cases, not routine operations - - Asynchronous processing: The reset completes immediately, but re-evaluation - happens in the background - - Args: - alert_id: The Metronome ID of the threshold notification - - customer_id: The Metronome ID of the customer - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._post( - "/v1/customer-alerts/reset", - body=maybe_transform( - { - "alert_id": alert_id, - "customer_id": customer_id, - }, - alert_reset_params.AlertResetParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class AsyncAlertsResource(AsyncAPIResource): - """ - [Alerts](https://docs.metronome.com/connecting-metronome/alerts/) monitor customer spending, balances, and other billing factors. Use these endpoints to create, retrieve, and archive customer alerts. To view sample alert payloads by alert type, navigate [here.](https://docs.metronome.com/manage-product-access/create-manage-alerts/#webhook-notifications) - """ - - @cached_property - def with_raw_response(self) -> AsyncAlertsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncAlertsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncAlertsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncAlertsResourceWithStreamingResponse(self) - - async def retrieve( - self, - *, - alert_id: str, - customer_id: str, - group_values: Iterable[alert_retrieve_params.GroupValue] | Omit = omit, - plans_or_contracts: Literal["PLANS", "CONTRACTS"] | Omit = omit, - seat_filter: alert_retrieve_params.SeatFilter | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AlertRetrieveResponse: - """ - Retrieve the real-time evaluation status for a specific threshold - notification-customer pair. This endpoint provides instant visibility into - whether a customer has triggered a threshold notification condition, enabling - you to monitor account health and take proactive action based on current - threshold notification states. - - ### Use this endpoint to: - - - Check if a specific customer is currently violating an threshold notification - (`in_alarm` status) - - Verify threshold notification configuration details and threshold values for a - customer - - Monitor the evaluation state of newly created or recently modified threshold - notification - - Build dashboards or automated workflows that respond to specific threshold - notification conditions - - Validate threshold notification behavior before deploying to production - customers - - Integrate threshold notification status checks into customer support tools or - admin interfaces - - ### Key response fields: - - A CustomerAlert object containing: - - - `customer_status`: The current evaluation state - - - `ok` - Customer is within acceptable thresholds - - `in_alarm` - Customer has breached the threshold for the notification - - `evaluating` - Notification is currently being evaluated (typically during - initial setup) - - `null` - Notification has been archived - - `triggered_by`: Additional context about what caused the notification to - trigger (when applicable) - - alert: Complete threshold notification configuration including: - - Notification ID, name, and type - - Current threshold values and credit type information - - Notification status (enabled, disabled, or archived) - - Last update timestamp - - Any applied filters (credit grant types, custom fields, group values) - - ### Usage guidelines: - - - Customer status: Returns the current evaluation state, not historical data. - For threshold notification history, use webhook notifications or event logs - - Required parameters: Both customer_id and alert_id must be valid UUIDs that - exist in your organization - - Archived notifications: Returns null for customer_status if the notification - has been archived, but still includes the notification configuration details - - Performance considerations: This endpoint queries live evaluation state, - making it ideal for real-time monitoring but not for bulk status checks - - Integration patterns: Best used for on-demand status checks in response to - user actions or as part of targeted monitoring workflows - - Error handling: Returns 404 if either the customer or alert_id doesn't exist - or isn't accessible to your organization - - Args: - alert_id: The Metronome ID of the threshold notification - - customer_id: The Metronome ID of the customer - - group_values: Only present for `spend_threshold_reached` notifications. Retrieve the - notification for a specific group key-value pair. - - plans_or_contracts: When parallel threshold notifications are enabled during migration, this flag - denotes whether to fetch notifications for plans or contracts. - - seat_filter: Only allowed for `low_remaining_seat_balance_reached` notifications. This - filters alerts by the seat group key-value pair. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/customer-alerts/get", - body=await async_maybe_transform( - { - "alert_id": alert_id, - "customer_id": customer_id, - "group_values": group_values, - "plans_or_contracts": plans_or_contracts, - "seat_filter": seat_filter, - }, - alert_retrieve_params.AlertRetrieveParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=AlertRetrieveResponse, - ) - - def list( - self, - *, - customer_id: str, - next_page: str | Omit = omit, - alert_statuses: List[Literal["ENABLED", "DISABLED", "ARCHIVED"]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[CustomerAlert, AsyncCursorPageWithoutLimit[CustomerAlert]]: - """ - Retrieve all threshold notification configurations and their current statuses - for a specific customer in a single API call. This endpoint provides a - comprehensive view of all threshold notification monitoring a customer account. - - ### Use this endpoint to: - - - Display all active threshold notifications for a customer in dashboards or - admin panels - - Quickly identify which threshold notifications a customer is currently - triggering - - Audit threshold notification coverage for specific accounts - - Filter threshold notifications by status (enabled, disabled, or archived) - - ### Key response fields: - - - data: Array of CustomerAlert objects, each containing: - - Current evaluation status (`ok`, `in_alarm`, `evaluating`, or `null`) - - Complete threshold notification configuration and threshold details - - Threshold notification metadata including type, name, and last update time - - next_page: Pagination cursor for retrieving additional results - - ### Usage guidelines: - - - Default behavior: Returns only enabled threshold notifications unless - `alert_statuses` filter is specified - - Pagination: Use the `next_page` cursor to retrieve all results for customers - with many notifications - - Performance: Efficiently retrieves multiple threshold notification statuses in - a single request instead of making individual calls - - Filtering: Pass the `alert_statuses` array to include disabled or archived - threshold notifications in results - - Args: - customer_id: The Metronome ID of the customer - - next_page: Cursor that indicates where the next page of results should start. - - alert_statuses: Optionally filter by threshold notification status. If absent, only enabled - notifications will be returned. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/customer-alerts/list", - page=AsyncCursorPageWithoutLimit[CustomerAlert], - body=maybe_transform( - { - "customer_id": customer_id, - "alert_statuses": alert_statuses, - }, - alert_list_params.AlertListParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"next_page": next_page}, alert_list_params.AlertListParams), - ), - model=CustomerAlert, - method="post", - ) - - async def reset( - self, - *, - alert_id: str, - customer_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - Force an immediate re-evaluation of a specific threshold notification for a - customer, clearing any previous state and triggering a fresh assessment against - current thresholds. This endpoint ensures threshold notification accuracy after - configuration changes or data corrections. - - ### Use this endpoint to: - - - Clear false positive threshold notifications after fixing data issues - - Re-evaluate threshold notifications after adjusting customer balances or - credits - - Test threshold notification behavior during development and debugging - - Resolve stuck threshold notification that may be in an incorrect state - - Trigger immediate evaluation after threshold modifications - - ### Key response fields: - - - 200 Success: Confirmation that the threshold notification has been reset and - re-evaluation initiated - - No response body is returned - the operation completes asynchronously - - ### Usage guidelines: - - - Immediate effect: Triggers re-evaluation instantly, which may result in new - webhook notifications if thresholds are breached - - State clearing: Removes any cached evaluation state, ensuring a fresh - assessment - - Use sparingly: Intended for exceptional cases, not routine operations - - Asynchronous processing: The reset completes immediately, but re-evaluation - happens in the background - - Args: - alert_id: The Metronome ID of the threshold notification - - customer_id: The Metronome ID of the customer - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._post( - "/v1/customer-alerts/reset", - body=await async_maybe_transform( - { - "alert_id": alert_id, - "customer_id": customer_id, - }, - alert_reset_params.AlertResetParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class AlertsResourceWithRawResponse: - def __init__(self, alerts: AlertsResource) -> None: - self._alerts = alerts - - self.retrieve = to_raw_response_wrapper( - alerts.retrieve, - ) - self.list = to_raw_response_wrapper( - alerts.list, - ) - self.reset = to_raw_response_wrapper( - alerts.reset, - ) - - -class AsyncAlertsResourceWithRawResponse: - def __init__(self, alerts: AsyncAlertsResource) -> None: - self._alerts = alerts - - self.retrieve = async_to_raw_response_wrapper( - alerts.retrieve, - ) - self.list = async_to_raw_response_wrapper( - alerts.list, - ) - self.reset = async_to_raw_response_wrapper( - alerts.reset, - ) - - -class AlertsResourceWithStreamingResponse: - def __init__(self, alerts: AlertsResource) -> None: - self._alerts = alerts - - self.retrieve = to_streamed_response_wrapper( - alerts.retrieve, - ) - self.list = to_streamed_response_wrapper( - alerts.list, - ) - self.reset = to_streamed_response_wrapper( - alerts.reset, - ) - - -class AsyncAlertsResourceWithStreamingResponse: - def __init__(self, alerts: AsyncAlertsResource) -> None: - self._alerts = alerts - - self.retrieve = async_to_streamed_response_wrapper( - alerts.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - alerts.list, - ) - self.reset = async_to_streamed_response_wrapper( - alerts.reset, - ) diff --git a/src/metronome/resources/v1/customers/billing_config.py b/src/metronome/resources/v1/customers/billing_config.py deleted file mode 100644 index 62bf30a4b..000000000 --- a/src/metronome/resources/v1/customers/billing_config.py +++ /dev/null @@ -1,547 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal - -import httpx - -from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ...._base_client import make_request_options -from ....types.v1.customers import billing_config_create_params -from ....types.v1.customers.billing_config_retrieve_response import BillingConfigRetrieveResponse - -__all__ = ["BillingConfigResource", "AsyncBillingConfigResource"] - - -class BillingConfigResource(SyncAPIResource): - """ - [Customers](https://docs.metronome.com/provisioning/create-customers/) in Metronome represent your users for all billing and reporting. Use these endpoints to create, retrieve, update, and archive customers and their billing configuration. - """ - - @cached_property - def with_raw_response(self) -> BillingConfigResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return BillingConfigResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> BillingConfigResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return BillingConfigResourceWithStreamingResponse(self) - - def create( - self, - *, - customer_id: str, - billing_provider_type: Literal[ - "aws_marketplace", - "stripe", - "netsuite", - "custom", - "azure_marketplace", - "quickbooks_online", - "workday", - "gcp_marketplace", - "metronome", - ], - billing_provider_customer_id: str, - aws_customer_account_id: str | Omit = omit, - aws_customer_id: str | Omit = omit, - aws_product_code: str | Omit = omit, - aws_region: Literal[ - "af-south-1", - "ap-east-1", - "ap-northeast-1", - "ap-northeast-2", - "ap-northeast-3", - "ap-south-1", - "ap-southeast-1", - "ap-southeast-2", - "ca-central-1", - "cn-north-1", - "cn-northwest-1", - "eu-central-1", - "eu-north-1", - "eu-south-1", - "eu-west-1", - "eu-west-2", - "eu-west-3", - "me-south-1", - "sa-east-1", - "us-east-1", - "us-east-2", - "us-gov-east-1", - "us-gov-west-1", - "us-west-1", - "us-west-2", - ] - | Omit = omit, - stripe_collection_method: Literal[ - "charge_automatically", "send_invoice", "auto_charge_payment_intent", "manually_charge_payment_intent" - ] - | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """Set the billing configuration for a given customer. - - This is a Plans (deprecated) - endpoint. New clients should implement using Contracts. - - Args: - billing_provider_customer_id: The customer ID in the billing provider's system. For Azure, this is the - subscription ID. - - stripe_collection_method: - The collection method for the customer's invoices. NOTE: - `auto_charge_payment_intent` and `manually_charge_payment_intent` are in beta. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - if not billing_provider_type: - raise ValueError( - f"Expected a non-empty value for `billing_provider_type` but received {billing_provider_type!r}" - ) - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._post( - f"/v1/customers/{customer_id}/billing-config/{billing_provider_type}", - body=maybe_transform( - { - "billing_provider_customer_id": billing_provider_customer_id, - "aws_customer_account_id": aws_customer_account_id, - "aws_customer_id": aws_customer_id, - "aws_product_code": aws_product_code, - "aws_region": aws_region, - "stripe_collection_method": stripe_collection_method, - }, - billing_config_create_params.BillingConfigCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def retrieve( - self, - *, - customer_id: str, - billing_provider_type: Literal[ - "aws_marketplace", - "stripe", - "netsuite", - "custom", - "azure_marketplace", - "quickbooks_online", - "workday", - "gcp_marketplace", - "metronome", - ], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> BillingConfigRetrieveResponse: - """Fetch the billing configuration for the given customer. - - This is a Plans - (deprecated) endpoint. New clients should implement using Contracts. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - if not billing_provider_type: - raise ValueError( - f"Expected a non-empty value for `billing_provider_type` but received {billing_provider_type!r}" - ) - return self._get( - f"/v1/customers/{customer_id}/billing-config/{billing_provider_type}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=BillingConfigRetrieveResponse, - ) - - def delete( - self, - *, - customer_id: str, - billing_provider_type: Literal[ - "aws_marketplace", - "stripe", - "netsuite", - "custom", - "azure_marketplace", - "quickbooks_online", - "workday", - "gcp_marketplace", - "metronome", - ], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """Delete the billing configuration for a given customer. - - Note: this is unsupported - for Azure and AWS Marketplace customers. This is a Plans (deprecated) endpoint. - New clients should implement using Contracts. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - if not billing_provider_type: - raise ValueError( - f"Expected a non-empty value for `billing_provider_type` but received {billing_provider_type!r}" - ) - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._delete( - f"/v1/customers/{customer_id}/billing-config/{billing_provider_type}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class AsyncBillingConfigResource(AsyncAPIResource): - """ - [Customers](https://docs.metronome.com/provisioning/create-customers/) in Metronome represent your users for all billing and reporting. Use these endpoints to create, retrieve, update, and archive customers and their billing configuration. - """ - - @cached_property - def with_raw_response(self) -> AsyncBillingConfigResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncBillingConfigResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncBillingConfigResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncBillingConfigResourceWithStreamingResponse(self) - - async def create( - self, - *, - customer_id: str, - billing_provider_type: Literal[ - "aws_marketplace", - "stripe", - "netsuite", - "custom", - "azure_marketplace", - "quickbooks_online", - "workday", - "gcp_marketplace", - "metronome", - ], - billing_provider_customer_id: str, - aws_customer_account_id: str | Omit = omit, - aws_customer_id: str | Omit = omit, - aws_product_code: str | Omit = omit, - aws_region: Literal[ - "af-south-1", - "ap-east-1", - "ap-northeast-1", - "ap-northeast-2", - "ap-northeast-3", - "ap-south-1", - "ap-southeast-1", - "ap-southeast-2", - "ca-central-1", - "cn-north-1", - "cn-northwest-1", - "eu-central-1", - "eu-north-1", - "eu-south-1", - "eu-west-1", - "eu-west-2", - "eu-west-3", - "me-south-1", - "sa-east-1", - "us-east-1", - "us-east-2", - "us-gov-east-1", - "us-gov-west-1", - "us-west-1", - "us-west-2", - ] - | Omit = omit, - stripe_collection_method: Literal[ - "charge_automatically", "send_invoice", "auto_charge_payment_intent", "manually_charge_payment_intent" - ] - | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """Set the billing configuration for a given customer. - - This is a Plans (deprecated) - endpoint. New clients should implement using Contracts. - - Args: - billing_provider_customer_id: The customer ID in the billing provider's system. For Azure, this is the - subscription ID. - - stripe_collection_method: - The collection method for the customer's invoices. NOTE: - `auto_charge_payment_intent` and `manually_charge_payment_intent` are in beta. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - if not billing_provider_type: - raise ValueError( - f"Expected a non-empty value for `billing_provider_type` but received {billing_provider_type!r}" - ) - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._post( - f"/v1/customers/{customer_id}/billing-config/{billing_provider_type}", - body=await async_maybe_transform( - { - "billing_provider_customer_id": billing_provider_customer_id, - "aws_customer_account_id": aws_customer_account_id, - "aws_customer_id": aws_customer_id, - "aws_product_code": aws_product_code, - "aws_region": aws_region, - "stripe_collection_method": stripe_collection_method, - }, - billing_config_create_params.BillingConfigCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - async def retrieve( - self, - *, - customer_id: str, - billing_provider_type: Literal[ - "aws_marketplace", - "stripe", - "netsuite", - "custom", - "azure_marketplace", - "quickbooks_online", - "workday", - "gcp_marketplace", - "metronome", - ], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> BillingConfigRetrieveResponse: - """Fetch the billing configuration for the given customer. - - This is a Plans - (deprecated) endpoint. New clients should implement using Contracts. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - if not billing_provider_type: - raise ValueError( - f"Expected a non-empty value for `billing_provider_type` but received {billing_provider_type!r}" - ) - return await self._get( - f"/v1/customers/{customer_id}/billing-config/{billing_provider_type}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=BillingConfigRetrieveResponse, - ) - - async def delete( - self, - *, - customer_id: str, - billing_provider_type: Literal[ - "aws_marketplace", - "stripe", - "netsuite", - "custom", - "azure_marketplace", - "quickbooks_online", - "workday", - "gcp_marketplace", - "metronome", - ], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """Delete the billing configuration for a given customer. - - Note: this is unsupported - for Azure and AWS Marketplace customers. This is a Plans (deprecated) endpoint. - New clients should implement using Contracts. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - if not billing_provider_type: - raise ValueError( - f"Expected a non-empty value for `billing_provider_type` but received {billing_provider_type!r}" - ) - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._delete( - f"/v1/customers/{customer_id}/billing-config/{billing_provider_type}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class BillingConfigResourceWithRawResponse: - def __init__(self, billing_config: BillingConfigResource) -> None: - self._billing_config = billing_config - - self.create = to_raw_response_wrapper( - billing_config.create, - ) - self.retrieve = to_raw_response_wrapper( - billing_config.retrieve, - ) - self.delete = to_raw_response_wrapper( - billing_config.delete, - ) - - -class AsyncBillingConfigResourceWithRawResponse: - def __init__(self, billing_config: AsyncBillingConfigResource) -> None: - self._billing_config = billing_config - - self.create = async_to_raw_response_wrapper( - billing_config.create, - ) - self.retrieve = async_to_raw_response_wrapper( - billing_config.retrieve, - ) - self.delete = async_to_raw_response_wrapper( - billing_config.delete, - ) - - -class BillingConfigResourceWithStreamingResponse: - def __init__(self, billing_config: BillingConfigResource) -> None: - self._billing_config = billing_config - - self.create = to_streamed_response_wrapper( - billing_config.create, - ) - self.retrieve = to_streamed_response_wrapper( - billing_config.retrieve, - ) - self.delete = to_streamed_response_wrapper( - billing_config.delete, - ) - - -class AsyncBillingConfigResourceWithStreamingResponse: - def __init__(self, billing_config: AsyncBillingConfigResource) -> None: - self._billing_config = billing_config - - self.create = async_to_streamed_response_wrapper( - billing_config.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - billing_config.retrieve, - ) - self.delete = async_to_streamed_response_wrapper( - billing_config.delete, - ) diff --git a/src/metronome/resources/v1/customers/commits.py b/src/metronome/resources/v1/customers/commits.py deleted file mode 100644 index b4373e761..000000000 --- a/src/metronome/resources/v1/customers/commits.py +++ /dev/null @@ -1,865 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable -from datetime import datetime -from typing_extensions import Literal - -import httpx - -from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ....pagination import SyncBodyCursorPage, AsyncBodyCursorPage -from ...._base_client import AsyncPaginator, make_request_options -from ....types.v1.customers import commit_list_params, commit_create_params, commit_update_end_date_params -from ....types.shared.commit import Commit -from ....types.v1.customers.commit_create_response import CommitCreateResponse -from ....types.shared_params.commit_specifier_input import CommitSpecifierInput -from ....types.v1.customers.commit_update_end_date_response import CommitUpdateEndDateResponse - -__all__ = ["CommitsResource", "AsyncCommitsResource"] - - -class CommitsResource(SyncAPIResource): - """Credits and commits are used to manage customer balances.""" - - @cached_property - def with_raw_response(self) -> CommitsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return CommitsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> CommitsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return CommitsResourceWithStreamingResponse(self) - - def create( - self, - *, - access_schedule: commit_create_params.AccessSchedule, - customer_id: str, - priority: float, - product_id: str, - type: Literal["PREPAID", "POSTPAID"], - applicable_contract_ids: SequenceNotStr[str] | Omit = omit, - applicable_product_ids: SequenceNotStr[str] | Omit = omit, - applicable_product_tags: SequenceNotStr[str] | Omit = omit, - custom_fields: Dict[str, str] | Omit = omit, - description: str | Omit = omit, - invoice_contract_id: str | Omit = omit, - invoice_schedule: commit_create_params.InvoiceSchedule | Omit = omit, - name: str | Omit = omit, - netsuite_sales_order_id: str | Omit = omit, - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] | Omit = omit, - salesforce_opportunity_id: str | Omit = omit, - specifiers: Iterable[CommitSpecifierInput] | Omit = omit, - uniqueness_key: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CommitCreateResponse: - """ - Creates customer-level commits that establish spending commitments for customers - across their Metronome usage. Commits represent contracted spending obligations - that can be either prepaid (paid upfront) or postpaid (billed later). - - Note: In most cases, you should add commitments directly to customer contracts - using the contract/create or contract/edit APIs. - - ### Use this endpoint to: - - Use this endpoint when you need to establish customer-level spending commitments - that can be applied across multiple contracts or scoped to specific contracts. - Customer-level commits are ideal for: - - - Enterprise-wide minimum spending agreements that span multiple contracts - - Multi-contract volume commitments with shared spending pools - - Cross-contract discount tiers based on aggregate usage - - #### Commit type Requirements: - - - You must specify either "prepaid" or "postpaid" as the commit type: - - Prepaid commits: Customer pays upfront; invoice_schedule is optional (if - omitted, creates a commit without an invoice) - - Postpaid commits: Customer pays when the commitment expires (the end of the - access_schedule); invoice_schedule is required and must match access_schedule - totals. - - #### Billing configuration: - - - invoice_contract_id is required for postpaid commits and for prepaid commits - with billing (only optional for free prepaid commits) unless do_not_invoice is - set to true - - For postpaid commits: access_schedule and invoice_schedule must have matching - amounts - - For postpaid commits: only one schedule item is allowed in both schedules. - - #### Scoping flexibility: - - Customer-level commits can be configured in a few ways: - - - Contract-specific: Use the `applicable_contract_ids` field to limit the commit - to specific contracts - - Cross-contract: Leave `applicable_contract_ids` empty to allow the commit to - be used across all of the customer's contracts - - #### Product targeting: - - Commits can be scoped to specific products using applicable_product_ids, - applicable_product_tags, or specifiers, or left unrestricted to apply to all - products. - - #### Priority considerations: - - When multiple commits are applicable, the one with the lower priority value will - be consumed first. If there is a tie, contract level commits and credits will be - applied before customer level commits and credits. Plan your priority scheme - carefully to ensure commits are applied in the desired order. - - ### Usage guidelines: - - ⚠️ Preferred Alternative: In most cases, you should add commits directly to - contracts using the create contract or edit contract APIs instead of creating - customer-level commits. Contract-level commits provide better organization and - are the recommended approach for standard use cases. - - Args: - access_schedule: Schedule for distributing the commit to the customer. For "POSTPAID" commits - only one schedule item is allowed and amount must match invoice_schedule total. - - priority: If multiple credits or commits are applicable, the one with the lower priority - will apply first. - - product_id: ID of the fixed product associated with the commit. This is required because - products are used to invoice the commit amount. - - applicable_contract_ids: Which contract the commit applies to. If not provided, the commit applies to all - contracts. - - applicable_product_ids: Which products the commit applies to. If applicable_product_ids, - applicable_product_tags or specifiers are not provided, the commit applies to - all products. - - applicable_product_tags: Which tags the commit applies to. If applicable_product_ids, - applicable_product_tags or specifiers are not provided, the commit applies to - all products. - - custom_fields: Custom fields to be added eg. { "key1": "value1", "key2": "value2" } - - description: Used only in UI/API. It is not exposed to end customers. - - invoice_contract_id: The contract that this commit will be billed on. This is required for "POSTPAID" - commits and for "PREPAID" commits unless there is no invoice schedule above - (i.e., the commit is 'free'), or if do_not_invoice is set to true. - - invoice_schedule: Required for "POSTPAID" commits: the true up invoice will be generated at this - time and only one schedule item is allowed; the total must match - accesss_schedule amount. Optional for "PREPAID" commits: if not provided, this - will be a "complimentary" commit with no invoice. - - name: displayed on invoices - - netsuite_sales_order_id: This field's availability is dependent on your client's configuration. - - salesforce_opportunity_id: This field's availability is dependent on your client's configuration. - - specifiers: List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - - uniqueness_key: Prevents the creation of duplicates. If a request to create a commit or credit - is made with a uniqueness key that was previously used to create a commit or - credit, a new record will not be created and the request will fail with a 409 - error. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contracts/customerCommits/create", - body=maybe_transform( - { - "access_schedule": access_schedule, - "customer_id": customer_id, - "priority": priority, - "product_id": product_id, - "type": type, - "applicable_contract_ids": applicable_contract_ids, - "applicable_product_ids": applicable_product_ids, - "applicable_product_tags": applicable_product_tags, - "custom_fields": custom_fields, - "description": description, - "invoice_contract_id": invoice_contract_id, - "invoice_schedule": invoice_schedule, - "name": name, - "netsuite_sales_order_id": netsuite_sales_order_id, - "rate_type": rate_type, - "salesforce_opportunity_id": salesforce_opportunity_id, - "specifiers": specifiers, - "uniqueness_key": uniqueness_key, - }, - commit_create_params.CommitCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CommitCreateResponse, - ) - - def list( - self, - *, - customer_id: str, - commit_id: str | Omit = omit, - covering_date: Union[str, datetime] | Omit = omit, - effective_before: Union[str, datetime] | Omit = omit, - include_archived: bool | Omit = omit, - include_balance: bool | Omit = omit, - include_contract_commits: bool | Omit = omit, - include_ledgers: bool | Omit = omit, - limit: int | Omit = omit, - next_page: str | Omit = omit, - starting_at: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncBodyCursorPage[Commit]: - """ - Retrieve all commit agreements for a customer, including both prepaid and - postpaid commitments. This endpoint provides comprehensive visibility into - contractual spending obligations, enabling you to track commitment utilization - and manage customer contracts effectively. - - ### Use this endpoint to: - - - Display commitment balances and utilization in customer dashboards - - Track prepaid commitment drawdown and remaining balances - - Monitor postpaid commitment progress toward minimum thresholds - - Build commitment tracking and forecasting tools - - Show commitment history with optional ledger details - - Manage rollover balances between contract periods - - ### Key response fields: - - An array of Commit objects containing: - - - Commit type: PREPAID (pay upfront) or POSTPAID (pay at true-up) - - Rate type: COMMIT_RATE (discounted) or LIST_RATE (standard pricing) - - Access schedule: When commitment funds become available - - Invoice schedule: When the customer is billed - - Product targeting: Which product(s) usage is eligible to draw from this commit - - Optional ledger entries: Transaction history (if `include_ledgers=true`) - - Balance information: Current available amount (if `include_balance=true`) - - Rollover settings: Fraction of unused amount that carries forward - - ### Usage guidelines: - - - Pagination: Results limited to 25 commits per page; use 'next_page' for more - - Date filtering options: - - `covering_date`: Commits active on a specific date - - `starting_at`: Commits with access on/after a date - - `effective_before`: Commits with access before a date (exclusive) - - Scope options: - - `include_contract_commits`: Include contract-level commits (not just - customer-level) - - `include_archived`: Include archived commits and commits from archived - contracts - - Performance considerations: - - include_ledgers: Adds detailed transaction history (slower) - - include_balance: Adds current balance calculation (slower) - - Optional filtering: Use commit_id to retrieve a specific commit - - Args: - covering_date: Include only commits that have access schedules that "cover" the provided date - - effective_before: Include only commits that have any access before the provided date (exclusive) - - include_archived: Include archived commits and commits from archived contracts. - - include_balance: Include the balance in the response. Setting this flag may cause the query to be - slower. - - include_contract_commits: Include commits on the contract level. - - include_ledgers: Include commit ledgers in the response. Setting this flag may cause the query to - be slower. - - limit: The maximum number of commits to return. Defaults to 25. - - next_page: The next page token from a previous response. - - starting_at: Include only commits that have any access on or after the provided date - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/contracts/customerCommits/list", - page=SyncBodyCursorPage[Commit], - body=maybe_transform( - { - "customer_id": customer_id, - "commit_id": commit_id, - "covering_date": covering_date, - "effective_before": effective_before, - "include_archived": include_archived, - "include_balance": include_balance, - "include_contract_commits": include_contract_commits, - "include_ledgers": include_ledgers, - "limit": limit, - "next_page": next_page, - "starting_at": starting_at, - }, - commit_list_params.CommitListParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - model=Commit, - method="post", - ) - - def update_end_date( - self, - *, - commit_id: str, - customer_id: str, - access_ending_before: Union[str, datetime] | Omit = omit, - invoices_ending_before: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CommitUpdateEndDateResponse: - """ - Shortens the end date of a prepaid commit to terminate it earlier than - originally scheduled. Use this endpoint when you need to cancel or reduce the - duration of an existing prepaid commit. Only works with prepaid commit types and - can only move the end date forward (earlier), not extend it. - - ### Usage guidelines: - - To extend commit end dates or make other comprehensive edits, use the 'edit - commit' endpoint instead. - - Args: - commit_id: ID of the commit to update. Only supports "PREPAID" commits. - - customer_id: ID of the customer whose commit is to be updated - - access_ending_before: RFC 3339 timestamp indicating when access to the commit will end and it will no - longer be possible to draw it down (exclusive). If not provided, the access will - not be updated. - - invoices_ending_before: RFC 3339 timestamp indicating when the commit will stop being invoiced - (exclusive). If not provided, the invoice schedule will not be updated. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contracts/customerCommits/updateEndDate", - body=maybe_transform( - { - "commit_id": commit_id, - "customer_id": customer_id, - "access_ending_before": access_ending_before, - "invoices_ending_before": invoices_ending_before, - }, - commit_update_end_date_params.CommitUpdateEndDateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CommitUpdateEndDateResponse, - ) - - -class AsyncCommitsResource(AsyncAPIResource): - """Credits and commits are used to manage customer balances.""" - - @cached_property - def with_raw_response(self) -> AsyncCommitsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncCommitsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncCommitsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncCommitsResourceWithStreamingResponse(self) - - async def create( - self, - *, - access_schedule: commit_create_params.AccessSchedule, - customer_id: str, - priority: float, - product_id: str, - type: Literal["PREPAID", "POSTPAID"], - applicable_contract_ids: SequenceNotStr[str] | Omit = omit, - applicable_product_ids: SequenceNotStr[str] | Omit = omit, - applicable_product_tags: SequenceNotStr[str] | Omit = omit, - custom_fields: Dict[str, str] | Omit = omit, - description: str | Omit = omit, - invoice_contract_id: str | Omit = omit, - invoice_schedule: commit_create_params.InvoiceSchedule | Omit = omit, - name: str | Omit = omit, - netsuite_sales_order_id: str | Omit = omit, - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] | Omit = omit, - salesforce_opportunity_id: str | Omit = omit, - specifiers: Iterable[CommitSpecifierInput] | Omit = omit, - uniqueness_key: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CommitCreateResponse: - """ - Creates customer-level commits that establish spending commitments for customers - across their Metronome usage. Commits represent contracted spending obligations - that can be either prepaid (paid upfront) or postpaid (billed later). - - Note: In most cases, you should add commitments directly to customer contracts - using the contract/create or contract/edit APIs. - - ### Use this endpoint to: - - Use this endpoint when you need to establish customer-level spending commitments - that can be applied across multiple contracts or scoped to specific contracts. - Customer-level commits are ideal for: - - - Enterprise-wide minimum spending agreements that span multiple contracts - - Multi-contract volume commitments with shared spending pools - - Cross-contract discount tiers based on aggregate usage - - #### Commit type Requirements: - - - You must specify either "prepaid" or "postpaid" as the commit type: - - Prepaid commits: Customer pays upfront; invoice_schedule is optional (if - omitted, creates a commit without an invoice) - - Postpaid commits: Customer pays when the commitment expires (the end of the - access_schedule); invoice_schedule is required and must match access_schedule - totals. - - #### Billing configuration: - - - invoice_contract_id is required for postpaid commits and for prepaid commits - with billing (only optional for free prepaid commits) unless do_not_invoice is - set to true - - For postpaid commits: access_schedule and invoice_schedule must have matching - amounts - - For postpaid commits: only one schedule item is allowed in both schedules. - - #### Scoping flexibility: - - Customer-level commits can be configured in a few ways: - - - Contract-specific: Use the `applicable_contract_ids` field to limit the commit - to specific contracts - - Cross-contract: Leave `applicable_contract_ids` empty to allow the commit to - be used across all of the customer's contracts - - #### Product targeting: - - Commits can be scoped to specific products using applicable_product_ids, - applicable_product_tags, or specifiers, or left unrestricted to apply to all - products. - - #### Priority considerations: - - When multiple commits are applicable, the one with the lower priority value will - be consumed first. If there is a tie, contract level commits and credits will be - applied before customer level commits and credits. Plan your priority scheme - carefully to ensure commits are applied in the desired order. - - ### Usage guidelines: - - ⚠️ Preferred Alternative: In most cases, you should add commits directly to - contracts using the create contract or edit contract APIs instead of creating - customer-level commits. Contract-level commits provide better organization and - are the recommended approach for standard use cases. - - Args: - access_schedule: Schedule for distributing the commit to the customer. For "POSTPAID" commits - only one schedule item is allowed and amount must match invoice_schedule total. - - priority: If multiple credits or commits are applicable, the one with the lower priority - will apply first. - - product_id: ID of the fixed product associated with the commit. This is required because - products are used to invoice the commit amount. - - applicable_contract_ids: Which contract the commit applies to. If not provided, the commit applies to all - contracts. - - applicable_product_ids: Which products the commit applies to. If applicable_product_ids, - applicable_product_tags or specifiers are not provided, the commit applies to - all products. - - applicable_product_tags: Which tags the commit applies to. If applicable_product_ids, - applicable_product_tags or specifiers are not provided, the commit applies to - all products. - - custom_fields: Custom fields to be added eg. { "key1": "value1", "key2": "value2" } - - description: Used only in UI/API. It is not exposed to end customers. - - invoice_contract_id: The contract that this commit will be billed on. This is required for "POSTPAID" - commits and for "PREPAID" commits unless there is no invoice schedule above - (i.e., the commit is 'free'), or if do_not_invoice is set to true. - - invoice_schedule: Required for "POSTPAID" commits: the true up invoice will be generated at this - time and only one schedule item is allowed; the total must match - accesss_schedule amount. Optional for "PREPAID" commits: if not provided, this - will be a "complimentary" commit with no invoice. - - name: displayed on invoices - - netsuite_sales_order_id: This field's availability is dependent on your client's configuration. - - salesforce_opportunity_id: This field's availability is dependent on your client's configuration. - - specifiers: List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - - uniqueness_key: Prevents the creation of duplicates. If a request to create a commit or credit - is made with a uniqueness key that was previously used to create a commit or - credit, a new record will not be created and the request will fail with a 409 - error. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contracts/customerCommits/create", - body=await async_maybe_transform( - { - "access_schedule": access_schedule, - "customer_id": customer_id, - "priority": priority, - "product_id": product_id, - "type": type, - "applicable_contract_ids": applicable_contract_ids, - "applicable_product_ids": applicable_product_ids, - "applicable_product_tags": applicable_product_tags, - "custom_fields": custom_fields, - "description": description, - "invoice_contract_id": invoice_contract_id, - "invoice_schedule": invoice_schedule, - "name": name, - "netsuite_sales_order_id": netsuite_sales_order_id, - "rate_type": rate_type, - "salesforce_opportunity_id": salesforce_opportunity_id, - "specifiers": specifiers, - "uniqueness_key": uniqueness_key, - }, - commit_create_params.CommitCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CommitCreateResponse, - ) - - def list( - self, - *, - customer_id: str, - commit_id: str | Omit = omit, - covering_date: Union[str, datetime] | Omit = omit, - effective_before: Union[str, datetime] | Omit = omit, - include_archived: bool | Omit = omit, - include_balance: bool | Omit = omit, - include_contract_commits: bool | Omit = omit, - include_ledgers: bool | Omit = omit, - limit: int | Omit = omit, - next_page: str | Omit = omit, - starting_at: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[Commit, AsyncBodyCursorPage[Commit]]: - """ - Retrieve all commit agreements for a customer, including both prepaid and - postpaid commitments. This endpoint provides comprehensive visibility into - contractual spending obligations, enabling you to track commitment utilization - and manage customer contracts effectively. - - ### Use this endpoint to: - - - Display commitment balances and utilization in customer dashboards - - Track prepaid commitment drawdown and remaining balances - - Monitor postpaid commitment progress toward minimum thresholds - - Build commitment tracking and forecasting tools - - Show commitment history with optional ledger details - - Manage rollover balances between contract periods - - ### Key response fields: - - An array of Commit objects containing: - - - Commit type: PREPAID (pay upfront) or POSTPAID (pay at true-up) - - Rate type: COMMIT_RATE (discounted) or LIST_RATE (standard pricing) - - Access schedule: When commitment funds become available - - Invoice schedule: When the customer is billed - - Product targeting: Which product(s) usage is eligible to draw from this commit - - Optional ledger entries: Transaction history (if `include_ledgers=true`) - - Balance information: Current available amount (if `include_balance=true`) - - Rollover settings: Fraction of unused amount that carries forward - - ### Usage guidelines: - - - Pagination: Results limited to 25 commits per page; use 'next_page' for more - - Date filtering options: - - `covering_date`: Commits active on a specific date - - `starting_at`: Commits with access on/after a date - - `effective_before`: Commits with access before a date (exclusive) - - Scope options: - - `include_contract_commits`: Include contract-level commits (not just - customer-level) - - `include_archived`: Include archived commits and commits from archived - contracts - - Performance considerations: - - include_ledgers: Adds detailed transaction history (slower) - - include_balance: Adds current balance calculation (slower) - - Optional filtering: Use commit_id to retrieve a specific commit - - Args: - covering_date: Include only commits that have access schedules that "cover" the provided date - - effective_before: Include only commits that have any access before the provided date (exclusive) - - include_archived: Include archived commits and commits from archived contracts. - - include_balance: Include the balance in the response. Setting this flag may cause the query to be - slower. - - include_contract_commits: Include commits on the contract level. - - include_ledgers: Include commit ledgers in the response. Setting this flag may cause the query to - be slower. - - limit: The maximum number of commits to return. Defaults to 25. - - next_page: The next page token from a previous response. - - starting_at: Include only commits that have any access on or after the provided date - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/contracts/customerCommits/list", - page=AsyncBodyCursorPage[Commit], - body=maybe_transform( - { - "customer_id": customer_id, - "commit_id": commit_id, - "covering_date": covering_date, - "effective_before": effective_before, - "include_archived": include_archived, - "include_balance": include_balance, - "include_contract_commits": include_contract_commits, - "include_ledgers": include_ledgers, - "limit": limit, - "next_page": next_page, - "starting_at": starting_at, - }, - commit_list_params.CommitListParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - model=Commit, - method="post", - ) - - async def update_end_date( - self, - *, - commit_id: str, - customer_id: str, - access_ending_before: Union[str, datetime] | Omit = omit, - invoices_ending_before: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CommitUpdateEndDateResponse: - """ - Shortens the end date of a prepaid commit to terminate it earlier than - originally scheduled. Use this endpoint when you need to cancel or reduce the - duration of an existing prepaid commit. Only works with prepaid commit types and - can only move the end date forward (earlier), not extend it. - - ### Usage guidelines: - - To extend commit end dates or make other comprehensive edits, use the 'edit - commit' endpoint instead. - - Args: - commit_id: ID of the commit to update. Only supports "PREPAID" commits. - - customer_id: ID of the customer whose commit is to be updated - - access_ending_before: RFC 3339 timestamp indicating when access to the commit will end and it will no - longer be possible to draw it down (exclusive). If not provided, the access will - not be updated. - - invoices_ending_before: RFC 3339 timestamp indicating when the commit will stop being invoiced - (exclusive). If not provided, the invoice schedule will not be updated. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contracts/customerCommits/updateEndDate", - body=await async_maybe_transform( - { - "commit_id": commit_id, - "customer_id": customer_id, - "access_ending_before": access_ending_before, - "invoices_ending_before": invoices_ending_before, - }, - commit_update_end_date_params.CommitUpdateEndDateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CommitUpdateEndDateResponse, - ) - - -class CommitsResourceWithRawResponse: - def __init__(self, commits: CommitsResource) -> None: - self._commits = commits - - self.create = to_raw_response_wrapper( - commits.create, - ) - self.list = to_raw_response_wrapper( - commits.list, - ) - self.update_end_date = to_raw_response_wrapper( - commits.update_end_date, - ) - - -class AsyncCommitsResourceWithRawResponse: - def __init__(self, commits: AsyncCommitsResource) -> None: - self._commits = commits - - self.create = async_to_raw_response_wrapper( - commits.create, - ) - self.list = async_to_raw_response_wrapper( - commits.list, - ) - self.update_end_date = async_to_raw_response_wrapper( - commits.update_end_date, - ) - - -class CommitsResourceWithStreamingResponse: - def __init__(self, commits: CommitsResource) -> None: - self._commits = commits - - self.create = to_streamed_response_wrapper( - commits.create, - ) - self.list = to_streamed_response_wrapper( - commits.list, - ) - self.update_end_date = to_streamed_response_wrapper( - commits.update_end_date, - ) - - -class AsyncCommitsResourceWithStreamingResponse: - def __init__(self, commits: AsyncCommitsResource) -> None: - self._commits = commits - - self.create = async_to_streamed_response_wrapper( - commits.create, - ) - self.list = async_to_streamed_response_wrapper( - commits.list, - ) - self.update_end_date = async_to_streamed_response_wrapper( - commits.update_end_date, - ) diff --git a/src/metronome/resources/v1/customers/credits.py b/src/metronome/resources/v1/customers/credits.py deleted file mode 100644 index 3a7e9e9b5..000000000 --- a/src/metronome/resources/v1/customers/credits.py +++ /dev/null @@ -1,779 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable -from datetime import datetime -from typing_extensions import Literal - -import httpx - -from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ....pagination import SyncBodyCursorPage, AsyncBodyCursorPage -from ...._base_client import AsyncPaginator, make_request_options -from ....types.v1.customers import credit_list_params, credit_create_params, credit_update_end_date_params -from ....types.shared.credit import Credit -from ....types.v1.customers.credit_create_response import CreditCreateResponse -from ....types.shared_params.commit_specifier_input import CommitSpecifierInput -from ....types.v1.customers.credit_update_end_date_response import CreditUpdateEndDateResponse - -__all__ = ["CreditsResource", "AsyncCreditsResource"] - - -class CreditsResource(SyncAPIResource): - """Credits and commits are used to manage customer balances.""" - - @cached_property - def with_raw_response(self) -> CreditsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return CreditsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> CreditsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return CreditsResourceWithStreamingResponse(self) - - def create( - self, - *, - access_schedule: credit_create_params.AccessSchedule, - customer_id: str, - priority: float, - product_id: str, - applicable_contract_ids: SequenceNotStr[str] | Omit = omit, - applicable_product_ids: SequenceNotStr[str] | Omit = omit, - applicable_product_tags: SequenceNotStr[str] | Omit = omit, - custom_fields: Dict[str, str] | Omit = omit, - description: str | Omit = omit, - name: str | Omit = omit, - netsuite_sales_order_id: str | Omit = omit, - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] | Omit = omit, - salesforce_opportunity_id: str | Omit = omit, - specifiers: Iterable[CommitSpecifierInput] | Omit = omit, - uniqueness_key: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CreditCreateResponse: - """ - Creates customer-level credits that provide spending allowances or free credit - balances for customers across their Metronome usage. Note: In most cases, you - should add credits directly to customer contracts using the contract/create or - contract/edit APIs. - - ### Use this endpoint to: - - Use this endpoint when you need to provision credits directly at the customer - level that can be applied across multiple contracts or scoped to specific - contracts. Customer-level credits are ideal for: - - - Customer onboarding incentives that apply globally - - Flexible spending allowances that aren't tied to a single contract - - Migration scenarios where you need to preserve existing customer balances - - #### Scoping flexibility: - - Customer-level credits can be configured in two ways: - - - Contract-specific: Use the applicable_contract_ids field to limit the credit - to specific contracts - - Cross-contract: Leave applicable_contract_ids empty to allow the credit to be - used across all of the customer's contracts - - #### Product Targeting: - - Credits can be scoped to specific products using `applicable_product_ids` or - `applicable_product_tags`, or left unrestricted to apply to all products. - - #### Priority considerations: - - When multiple credits are applicable, the one with the lower priority value will - be consumed first. If there is a tie, contract level commits and credits will be - applied before customer level commits and credits. Plan your priority scheme - carefully to ensure credits are applied in the desired order. - - #### Access Schedule Required: - - You must provide an `access_schedule` that defines when and how much credit - becomes available to the customer over time. This usually is aligned to the - contract schedule or starts immediately and is set to expire in the future. - - ### Usage Guidelines: - - ⚠️ Preferred Alternative: In most cases, you should add credits directly to - contracts using the contract/create or contract/edit APIs instead of creating - customer-level credits. Contract-level credits provide better organization, and - are easier for finance teams to recognize revenue, and are the recommended - approach for most use cases. - - Args: - access_schedule: Schedule for distributing the credit to the customer. - - priority: If multiple credits or commits are applicable, the one with the lower priority - will apply first. - - applicable_contract_ids: Which contract the credit applies to. If not provided, the credit applies to all - contracts. - - applicable_product_ids: Which products the credit applies to. If both applicable_product_ids and - applicable_product_tags are not provided, the credit applies to all products. - - applicable_product_tags: Which tags the credit applies to. If both applicable_product_ids and - applicable_product_tags are not provided, the credit applies to all products. - - custom_fields: Custom fields to be added eg. { "key1": "value1", "key2": "value2" } - - description: Used only in UI/API. It is not exposed to end customers. - - name: displayed on invoices - - netsuite_sales_order_id: This field's availability is dependent on your client's configuration. - - salesforce_opportunity_id: This field's availability is dependent on your client's configuration. - - specifiers: List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - - uniqueness_key: Prevents the creation of duplicates. If a request to create a commit or credit - is made with a uniqueness key that was previously used to create a commit or - credit, a new record will not be created and the request will fail with a 409 - error. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contracts/customerCredits/create", - body=maybe_transform( - { - "access_schedule": access_schedule, - "customer_id": customer_id, - "priority": priority, - "product_id": product_id, - "applicable_contract_ids": applicable_contract_ids, - "applicable_product_ids": applicable_product_ids, - "applicable_product_tags": applicable_product_tags, - "custom_fields": custom_fields, - "description": description, - "name": name, - "netsuite_sales_order_id": netsuite_sales_order_id, - "rate_type": rate_type, - "salesforce_opportunity_id": salesforce_opportunity_id, - "specifiers": specifiers, - "uniqueness_key": uniqueness_key, - }, - credit_create_params.CreditCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CreditCreateResponse, - ) - - def list( - self, - *, - customer_id: str, - covering_date: Union[str, datetime] | Omit = omit, - credit_id: str | Omit = omit, - effective_before: Union[str, datetime] | Omit = omit, - include_archived: bool | Omit = omit, - include_balance: bool | Omit = omit, - include_contract_credits: bool | Omit = omit, - include_ledgers: bool | Omit = omit, - limit: int | Omit = omit, - next_page: str | Omit = omit, - starting_at: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncBodyCursorPage[Credit]: - """ - Retrieve a detailed list of all credits available to a customer, including - promotional credits and contract-specific credits. This endpoint provides - comprehensive visibility into credit balances, access schedules, and usage - rules, enabling you to build credit management interfaces and track available - funding. - - ### Use this endpoint to: - - - Display all available credits in customer billing dashboards - - Show credit balances and expiration dates - - Track credit usage history with optional ledger details - - Build credit management and reporting tools - - Monitor promotional credit utilization • Support customer inquiries about - available credits - - ### Key response fields: - - An array of Credit objects containing: - - - Credit details: Name, priority, and which applicable products/tags it applies - to - - Product ID: The `product_id` of the credit. This is for external mapping into - your quote-to-cash stack, not the product it applies to. - - Access schedule: When credits become available and expire - - Optional ledger entries: Transaction history (if `include_ledgers=true`) - - Balance information: Current available amount (if `include_balance=true`) - - Metadata: Custom fields and usage specifiers - - ### Usage guidelines: - - - Pagination: Results limited to 25 commits per page; use next_page for more - - Date filtering options: - - `covering_date`: Credits active on a specific date - - `starting_at`: Credits with access on/after a date - - `effective_before`: Credits with access before a date (exclusive) - - Scope options: - - `include_contract_credits`: Include contract-level credits (not just - customer-level) - - `include_archived`: Include archived credits and credits from archived - contracts - - Performance considerations: - - `include_ledgers`: Adds detailed transaction history (slower) - - `include_balance`: Adds current balance calculation (slower) - - Optional filtering: Use credit_id to retrieve a specific commit - - Args: - covering_date: Return only credits that have access schedules that "cover" the provided date - - effective_before: Include only credits that have any access before the provided date (exclusive) - - include_archived: Include archived credits and credits from archived contracts. - - include_balance: Include the balance in the response. Setting this flag may cause the query to be - slower. - - include_contract_credits: Include credits on the contract level. - - include_ledgers: Include credit ledgers in the response. Setting this flag may cause the query to - be slower. - - limit: The maximum number of commits to return. Defaults to 25. - - next_page: The next page token from a previous response. - - starting_at: Include only credits that have any access on or after the provided date - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/contracts/customerCredits/list", - page=SyncBodyCursorPage[Credit], - body=maybe_transform( - { - "customer_id": customer_id, - "covering_date": covering_date, - "credit_id": credit_id, - "effective_before": effective_before, - "include_archived": include_archived, - "include_balance": include_balance, - "include_contract_credits": include_contract_credits, - "include_ledgers": include_ledgers, - "limit": limit, - "next_page": next_page, - "starting_at": starting_at, - }, - credit_list_params.CreditListParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - model=Credit, - method="post", - ) - - def update_end_date( - self, - *, - access_ending_before: Union[str, datetime], - credit_id: str, - customer_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CreditUpdateEndDateResponse: - """ - Shortens the end date of an existing customer credit to terminate it earlier - than originally scheduled. Only allows moving end dates forward (earlier), not - extending them. - - Note: To extend credit end dates or make comprehensive edits, use the 'edit - credit' endpoint instead. - - Args: - access_ending_before: RFC 3339 timestamp indicating when access to the credit will end and it will no - longer be possible to draw it down (exclusive). - - credit_id: ID of the commit to update - - customer_id: ID of the customer whose credit is to be updated - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/contracts/customerCredits/updateEndDate", - body=maybe_transform( - { - "access_ending_before": access_ending_before, - "credit_id": credit_id, - "customer_id": customer_id, - }, - credit_update_end_date_params.CreditUpdateEndDateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CreditUpdateEndDateResponse, - ) - - -class AsyncCreditsResource(AsyncAPIResource): - """Credits and commits are used to manage customer balances.""" - - @cached_property - def with_raw_response(self) -> AsyncCreditsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncCreditsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncCreditsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncCreditsResourceWithStreamingResponse(self) - - async def create( - self, - *, - access_schedule: credit_create_params.AccessSchedule, - customer_id: str, - priority: float, - product_id: str, - applicable_contract_ids: SequenceNotStr[str] | Omit = omit, - applicable_product_ids: SequenceNotStr[str] | Omit = omit, - applicable_product_tags: SequenceNotStr[str] | Omit = omit, - custom_fields: Dict[str, str] | Omit = omit, - description: str | Omit = omit, - name: str | Omit = omit, - netsuite_sales_order_id: str | Omit = omit, - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] | Omit = omit, - salesforce_opportunity_id: str | Omit = omit, - specifiers: Iterable[CommitSpecifierInput] | Omit = omit, - uniqueness_key: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CreditCreateResponse: - """ - Creates customer-level credits that provide spending allowances or free credit - balances for customers across their Metronome usage. Note: In most cases, you - should add credits directly to customer contracts using the contract/create or - contract/edit APIs. - - ### Use this endpoint to: - - Use this endpoint when you need to provision credits directly at the customer - level that can be applied across multiple contracts or scoped to specific - contracts. Customer-level credits are ideal for: - - - Customer onboarding incentives that apply globally - - Flexible spending allowances that aren't tied to a single contract - - Migration scenarios where you need to preserve existing customer balances - - #### Scoping flexibility: - - Customer-level credits can be configured in two ways: - - - Contract-specific: Use the applicable_contract_ids field to limit the credit - to specific contracts - - Cross-contract: Leave applicable_contract_ids empty to allow the credit to be - used across all of the customer's contracts - - #### Product Targeting: - - Credits can be scoped to specific products using `applicable_product_ids` or - `applicable_product_tags`, or left unrestricted to apply to all products. - - #### Priority considerations: - - When multiple credits are applicable, the one with the lower priority value will - be consumed first. If there is a tie, contract level commits and credits will be - applied before customer level commits and credits. Plan your priority scheme - carefully to ensure credits are applied in the desired order. - - #### Access Schedule Required: - - You must provide an `access_schedule` that defines when and how much credit - becomes available to the customer over time. This usually is aligned to the - contract schedule or starts immediately and is set to expire in the future. - - ### Usage Guidelines: - - ⚠️ Preferred Alternative: In most cases, you should add credits directly to - contracts using the contract/create or contract/edit APIs instead of creating - customer-level credits. Contract-level credits provide better organization, and - are easier for finance teams to recognize revenue, and are the recommended - approach for most use cases. - - Args: - access_schedule: Schedule for distributing the credit to the customer. - - priority: If multiple credits or commits are applicable, the one with the lower priority - will apply first. - - applicable_contract_ids: Which contract the credit applies to. If not provided, the credit applies to all - contracts. - - applicable_product_ids: Which products the credit applies to. If both applicable_product_ids and - applicable_product_tags are not provided, the credit applies to all products. - - applicable_product_tags: Which tags the credit applies to. If both applicable_product_ids and - applicable_product_tags are not provided, the credit applies to all products. - - custom_fields: Custom fields to be added eg. { "key1": "value1", "key2": "value2" } - - description: Used only in UI/API. It is not exposed to end customers. - - name: displayed on invoices - - netsuite_sales_order_id: This field's availability is dependent on your client's configuration. - - salesforce_opportunity_id: This field's availability is dependent on your client's configuration. - - specifiers: List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - - uniqueness_key: Prevents the creation of duplicates. If a request to create a commit or credit - is made with a uniqueness key that was previously used to create a commit or - credit, a new record will not be created and the request will fail with a 409 - error. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contracts/customerCredits/create", - body=await async_maybe_transform( - { - "access_schedule": access_schedule, - "customer_id": customer_id, - "priority": priority, - "product_id": product_id, - "applicable_contract_ids": applicable_contract_ids, - "applicable_product_ids": applicable_product_ids, - "applicable_product_tags": applicable_product_tags, - "custom_fields": custom_fields, - "description": description, - "name": name, - "netsuite_sales_order_id": netsuite_sales_order_id, - "rate_type": rate_type, - "salesforce_opportunity_id": salesforce_opportunity_id, - "specifiers": specifiers, - "uniqueness_key": uniqueness_key, - }, - credit_create_params.CreditCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CreditCreateResponse, - ) - - def list( - self, - *, - customer_id: str, - covering_date: Union[str, datetime] | Omit = omit, - credit_id: str | Omit = omit, - effective_before: Union[str, datetime] | Omit = omit, - include_archived: bool | Omit = omit, - include_balance: bool | Omit = omit, - include_contract_credits: bool | Omit = omit, - include_ledgers: bool | Omit = omit, - limit: int | Omit = omit, - next_page: str | Omit = omit, - starting_at: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[Credit, AsyncBodyCursorPage[Credit]]: - """ - Retrieve a detailed list of all credits available to a customer, including - promotional credits and contract-specific credits. This endpoint provides - comprehensive visibility into credit balances, access schedules, and usage - rules, enabling you to build credit management interfaces and track available - funding. - - ### Use this endpoint to: - - - Display all available credits in customer billing dashboards - - Show credit balances and expiration dates - - Track credit usage history with optional ledger details - - Build credit management and reporting tools - - Monitor promotional credit utilization • Support customer inquiries about - available credits - - ### Key response fields: - - An array of Credit objects containing: - - - Credit details: Name, priority, and which applicable products/tags it applies - to - - Product ID: The `product_id` of the credit. This is for external mapping into - your quote-to-cash stack, not the product it applies to. - - Access schedule: When credits become available and expire - - Optional ledger entries: Transaction history (if `include_ledgers=true`) - - Balance information: Current available amount (if `include_balance=true`) - - Metadata: Custom fields and usage specifiers - - ### Usage guidelines: - - - Pagination: Results limited to 25 commits per page; use next_page for more - - Date filtering options: - - `covering_date`: Credits active on a specific date - - `starting_at`: Credits with access on/after a date - - `effective_before`: Credits with access before a date (exclusive) - - Scope options: - - `include_contract_credits`: Include contract-level credits (not just - customer-level) - - `include_archived`: Include archived credits and credits from archived - contracts - - Performance considerations: - - `include_ledgers`: Adds detailed transaction history (slower) - - `include_balance`: Adds current balance calculation (slower) - - Optional filtering: Use credit_id to retrieve a specific commit - - Args: - covering_date: Return only credits that have access schedules that "cover" the provided date - - effective_before: Include only credits that have any access before the provided date (exclusive) - - include_archived: Include archived credits and credits from archived contracts. - - include_balance: Include the balance in the response. Setting this flag may cause the query to be - slower. - - include_contract_credits: Include credits on the contract level. - - include_ledgers: Include credit ledgers in the response. Setting this flag may cause the query to - be slower. - - limit: The maximum number of commits to return. Defaults to 25. - - next_page: The next page token from a previous response. - - starting_at: Include only credits that have any access on or after the provided date - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/contracts/customerCredits/list", - page=AsyncBodyCursorPage[Credit], - body=maybe_transform( - { - "customer_id": customer_id, - "covering_date": covering_date, - "credit_id": credit_id, - "effective_before": effective_before, - "include_archived": include_archived, - "include_balance": include_balance, - "include_contract_credits": include_contract_credits, - "include_ledgers": include_ledgers, - "limit": limit, - "next_page": next_page, - "starting_at": starting_at, - }, - credit_list_params.CreditListParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - model=Credit, - method="post", - ) - - async def update_end_date( - self, - *, - access_ending_before: Union[str, datetime], - credit_id: str, - customer_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CreditUpdateEndDateResponse: - """ - Shortens the end date of an existing customer credit to terminate it earlier - than originally scheduled. Only allows moving end dates forward (earlier), not - extending them. - - Note: To extend credit end dates or make comprehensive edits, use the 'edit - credit' endpoint instead. - - Args: - access_ending_before: RFC 3339 timestamp indicating when access to the credit will end and it will no - longer be possible to draw it down (exclusive). - - credit_id: ID of the commit to update - - customer_id: ID of the customer whose credit is to be updated - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/contracts/customerCredits/updateEndDate", - body=await async_maybe_transform( - { - "access_ending_before": access_ending_before, - "credit_id": credit_id, - "customer_id": customer_id, - }, - credit_update_end_date_params.CreditUpdateEndDateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CreditUpdateEndDateResponse, - ) - - -class CreditsResourceWithRawResponse: - def __init__(self, credits: CreditsResource) -> None: - self._credits = credits - - self.create = to_raw_response_wrapper( - credits.create, - ) - self.list = to_raw_response_wrapper( - credits.list, - ) - self.update_end_date = to_raw_response_wrapper( - credits.update_end_date, - ) - - -class AsyncCreditsResourceWithRawResponse: - def __init__(self, credits: AsyncCreditsResource) -> None: - self._credits = credits - - self.create = async_to_raw_response_wrapper( - credits.create, - ) - self.list = async_to_raw_response_wrapper( - credits.list, - ) - self.update_end_date = async_to_raw_response_wrapper( - credits.update_end_date, - ) - - -class CreditsResourceWithStreamingResponse: - def __init__(self, credits: CreditsResource) -> None: - self._credits = credits - - self.create = to_streamed_response_wrapper( - credits.create, - ) - self.list = to_streamed_response_wrapper( - credits.list, - ) - self.update_end_date = to_streamed_response_wrapper( - credits.update_end_date, - ) - - -class AsyncCreditsResourceWithStreamingResponse: - def __init__(self, credits: AsyncCreditsResource) -> None: - self._credits = credits - - self.create = async_to_streamed_response_wrapper( - credits.create, - ) - self.list = async_to_streamed_response_wrapper( - credits.list, - ) - self.update_end_date = async_to_streamed_response_wrapper( - credits.update_end_date, - ) diff --git a/src/metronome/resources/v1/customers/customers.py b/src/metronome/resources/v1/customers/customers.py deleted file mode 100644 index 3144f8f0e..000000000 --- a/src/metronome/resources/v1/customers/customers.py +++ /dev/null @@ -1,2135 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable, Optional -from datetime import datetime -from typing_extensions import Literal - -import httpx - -from .plans import ( - PlansResource, - AsyncPlansResource, - PlansResourceWithRawResponse, - AsyncPlansResourceWithRawResponse, - PlansResourceWithStreamingResponse, - AsyncPlansResourceWithStreamingResponse, -) -from .alerts import ( - AlertsResource, - AsyncAlertsResource, - AlertsResourceWithRawResponse, - AsyncAlertsResourceWithRawResponse, - AlertsResourceWithStreamingResponse, - AsyncAlertsResourceWithStreamingResponse, -) -from .commits import ( - CommitsResource, - AsyncCommitsResource, - CommitsResourceWithRawResponse, - AsyncCommitsResourceWithRawResponse, - CommitsResourceWithStreamingResponse, - AsyncCommitsResourceWithStreamingResponse, -) -from .credits import ( - CreditsResource, - AsyncCreditsResource, - CreditsResourceWithRawResponse, - AsyncCreditsResourceWithRawResponse, - CreditsResourceWithStreamingResponse, - AsyncCreditsResourceWithStreamingResponse, -) -from .invoices import ( - InvoicesResource, - AsyncInvoicesResource, - InvoicesResourceWithRawResponse, - AsyncInvoicesResourceWithRawResponse, - InvoicesResourceWithStreamingResponse, - AsyncInvoicesResourceWithStreamingResponse, -) -from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform -from ...._compat import cached_property -from ....types.v1 import ( - customer_list_params, - customer_create_params, - customer_archive_params, - customer_set_name_params, - customer_list_costs_params, - customer_update_config_params, - customer_preview_events_params, - customer_set_ingest_aliases_params, - customer_list_billable_metrics_params, - customer_set_billing_configurations_params, - customer_archive_billing_configurations_params, - customer_retrieve_billing_configurations_params, -) -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ....pagination import SyncCursorPage, AsyncCursorPage -from .billing_config import ( - BillingConfigResource, - AsyncBillingConfigResource, - BillingConfigResourceWithRawResponse, - AsyncBillingConfigResourceWithRawResponse, - BillingConfigResourceWithStreamingResponse, - AsyncBillingConfigResourceWithStreamingResponse, -) -from ...._base_client import AsyncPaginator, make_request_options -from .named_schedules import ( - NamedSchedulesResource, - AsyncNamedSchedulesResource, - NamedSchedulesResourceWithRawResponse, - AsyncNamedSchedulesResourceWithRawResponse, - NamedSchedulesResourceWithStreamingResponse, - AsyncNamedSchedulesResourceWithStreamingResponse, -) -from ....types.v1.customer_detail import CustomerDetail -from ....types.v1.customer_create_response import CustomerCreateResponse -from ....types.v1.customer_archive_response import CustomerArchiveResponse -from ....types.v1.customer_retrieve_response import CustomerRetrieveResponse -from ....types.v1.customer_set_name_response import CustomerSetNameResponse -from ....types.v1.customer_list_costs_response import CustomerListCostsResponse -from ....types.v1.customer_preview_events_response import CustomerPreviewEventsResponse -from ....types.v1.customer_list_billable_metrics_response import CustomerListBillableMetricsResponse -from ....types.v1.customer_set_billing_configurations_response import CustomerSetBillingConfigurationsResponse -from ....types.v1.customer_archive_billing_configurations_response import CustomerArchiveBillingConfigurationsResponse -from ....types.v1.customer_retrieve_billing_configurations_response import CustomerRetrieveBillingConfigurationsResponse - -__all__ = ["CustomersResource", "AsyncCustomersResource"] - - -class CustomersResource(SyncAPIResource): - @cached_property - def alerts(self) -> AlertsResource: - """ - [Alerts](https://docs.metronome.com/connecting-metronome/alerts/) monitor customer spending, balances, and other billing factors. Use these endpoints to create, retrieve, and archive customer alerts. To view sample alert payloads by alert type, navigate [here.](https://docs.metronome.com/manage-product-access/create-manage-alerts/#webhook-notifications) - """ - return AlertsResource(self._client) - - @cached_property - def plans(self) -> PlansResource: - """ - [Plans](https://docs.metronome.com/pricing-and-packaging/create-plans/) determine the base pricing for a customer. Use these endpoints to add a plan to a customer, end a customer plan, retrieve plans, and retrieve plan details. Create plans in the [Metronome app](https://app.metronome.com/plans). - """ - return PlansResource(self._client) - - @cached_property - def invoices(self) -> InvoicesResource: - """ - [Invoices](https://docs.metronome.com/invoicing/) reflect how much a customer spent during a period, which is the basis for billing. Metronome automatically generates invoices based upon your pricing, packaging, and usage events. Use these endpoints to retrieve invoices. - """ - return InvoicesResource(self._client) - - @cached_property - def billing_config(self) -> BillingConfigResource: - """ - [Customers](https://docs.metronome.com/provisioning/create-customers/) in Metronome represent your users for all billing and reporting. Use these endpoints to create, retrieve, update, and archive customers and their billing configuration. - """ - return BillingConfigResource(self._client) - - @cached_property - def commits(self) -> CommitsResource: - """Credits and commits are used to manage customer balances.""" - return CommitsResource(self._client) - - @cached_property - def credits(self) -> CreditsResource: - """Credits and commits are used to manage customer balances.""" - return CreditsResource(self._client) - - @cached_property - def named_schedules(self) -> NamedSchedulesResource: - """Named schedules are used for storing custom data that can change over time. - - Named schedules are often used in custom pricing logic. - """ - return NamedSchedulesResource(self._client) - - @cached_property - def with_raw_response(self) -> CustomersResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return CustomersResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> CustomersResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return CustomersResourceWithStreamingResponse(self) - - def create( - self, - *, - name: str, - billing_config: customer_create_params.BillingConfig | Omit = omit, - custom_fields: Dict[str, str] | Omit = omit, - customer_billing_provider_configurations: Iterable[customer_create_params.CustomerBillingProviderConfiguration] - | Omit = omit, - customer_revenue_system_configurations: Iterable[customer_create_params.CustomerRevenueSystemConfiguration] - | Omit = omit, - external_id: str | Omit = omit, - ingest_aliases: SequenceNotStr[str] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CustomerCreateResponse: - """ - Create a new customer in Metronome and optionally the billing configuration - (recommended) which dictates where invoices for the customer will be sent or - where payment will be collected. - - ### Use this endpoint to: - - Execute your customer provisioning workflows for either PLG motions, where - customers originate in your platform, or SLG motions, where customers originate - in your sales system. - - ### Key response fields: - - This end-point returns the `customer_id` created by the request. This id can be - used to fetch relevant billing configurations and create contracts. - - ### Example workflow: - - - Generally, Metronome recommends first creating the customer in the downstream - payment / ERP system when payment method is collected and then creating the - customer in Metronome using the response (i.e. `customer_id`) from the - downstream system. If you do not create a billing configuration on customer - creation, you can add it later. - - Once a customer is created, you can then create a contract for the customer. - In the contract creation process, you will need to add the customer billing - configuration to the contract to ensure Metronome invoices the customer - correctly. This is because a customer can have multiple configurations. - - As part of the customer creation process, set the ingest alias for the - customer which will ensure usage is accurately mapped to the customer. Ingest - aliases can be added or changed after the creation process as well. - - ### Usage guidelines: - - For details on different billing configurations for different systems, review - the `/setCustomerBillingConfiguration` end-point. - - Args: - name: This will be truncated to 160 characters if the provided name is longer. - - custom_fields: Custom fields to be added eg. { "key1": "value1", "key2": "value2" } - - external_id: (deprecated, use ingest_aliases instead) an alias that can be used to refer to - this customer in usage events - - ingest_aliases: Aliases that can be used to refer to this customer in usage events - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/customers", - body=maybe_transform( - { - "name": name, - "billing_config": billing_config, - "custom_fields": custom_fields, - "customer_billing_provider_configurations": customer_billing_provider_configurations, - "customer_revenue_system_configurations": customer_revenue_system_configurations, - "external_id": external_id, - "ingest_aliases": ingest_aliases, - }, - customer_create_params.CustomerCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CustomerCreateResponse, - ) - - def retrieve( - self, - *, - customer_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CustomerRetrieveResponse: - """Get detailed information for a specific customer by their Metronome ID. - - Returns - customer profile data including name, creation date, ingest aliases, - configuration settings, and custom fields. Use this endpoint to fetch complete - customer details for billing operations or account management. - - Note: If searching for a customer billing configuration, use the - `/getCustomerBillingConfigurations` endpoint. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - return self._get( - f"/v1/customers/{customer_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CustomerRetrieveResponse, - ) - - def list( - self, - *, - customer_ids: SequenceNotStr[str] | Omit = omit, - ingest_alias: str | Omit = omit, - limit: int | Omit = omit, - next_page: str | Omit = omit, - only_archived: bool | Omit = omit, - salesforce_account_ids: SequenceNotStr[str] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[CustomerDetail]: - """Gets a paginated list of all customers in your Metronome account. - - Use this - endpoint to browse your customer base, implement customer search functionality, - or sync customer data with external systems. Returns customer details including - IDs, names, and configuration settings. Supports filtering and pagination - parameters for efficient data retrieval. - - Args: - customer_ids: Filter the customer list by customer_id. Up to 100 ids can be provided. - - ingest_alias: Filter the customer list by ingest_alias - - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - only_archived: Filter the customer list to only return archived customers. By default, only - active customers are returned. - - salesforce_account_ids: Filter the customer list by salesforce_account_id. Up to 100 ids can be - provided. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/customers", - page=SyncCursorPage[CustomerDetail], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "customer_ids": customer_ids, - "ingest_alias": ingest_alias, - "limit": limit, - "next_page": next_page, - "only_archived": only_archived, - "salesforce_account_ids": salesforce_account_ids, - }, - customer_list_params.CustomerListParams, - ), - ), - model=CustomerDetail, - ) - - def archive( - self, - *, - id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CustomerArchiveResponse: - """Use this endpoint to archive a customer while preserving auditability. - - Archiving - a customer will automatically archive all contracts as of the current date and - void all corresponding invoices. Use this endpoint if a customer is onboarded by - mistake. - - ### Usage guidelines: - - - Once a customer is archived, it cannot be unarchived. - - Archived customers can still be viewed through the API or the UI for audit - purposes. - - Ingest aliases remain idempotent for archived customers. In order to reuse an - ingest alias, first remove the ingest alias from the customer prior to - archiving. - - Any notifications associated with the customer will no longer be triggered. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/customers/archive", - body=maybe_transform({"id": id}, customer_archive_params.CustomerArchiveParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CustomerArchiveResponse, - ) - - def archive_billing_configurations( - self, - *, - customer_billing_provider_configuration_ids: SequenceNotStr[str], - customer_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CustomerArchiveBillingConfigurationsResponse: - """ - Deprecate an existing billing configuration for a customer to handle churn or - billing and collection preference changes. Archiving a billing configuration - takes effect immediately. If there are active contracts using the configuration, - Metronome will archive the configuration on the contract and immediately stop - metering to downstream systems. - - ### Use this endpoint to: - - - Remove billing provider customer data and configurations when no longer needed - - Clean up test or deprecated billing provider configurations - - Free up uniqueness keys for reuse with new billing provider configurations - - Disable threshold recharge configurations associated with archived billing - providers - - ### Key response fields: - - A successful response returns: - - - `success`: Boolean indicating the operation completed successfully - - `error`: Null on success, error message on failure - - ### Usage guidelines: - - - Archiving a contract configuration during a grace period will result in the - invoice not being sent to the customer - - Automatically disables both spend-based and credit-based threshold recharge - configurations for contracts using the archived billing provider - - You can archive multiple configurations for a single customer in a single - request, but any validation failures for an individual configuration will - prevent the entire operation from succeeding - - Args: - customer_billing_provider_configuration_ids: Array of billing provider configuration IDs to archive - - customer_id: The customer ID the billing provider configurations belong to - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/archiveCustomerBillingProviderConfigurations", - body=maybe_transform( - { - "customer_billing_provider_configuration_ids": customer_billing_provider_configuration_ids, - "customer_id": customer_id, - }, - customer_archive_billing_configurations_params.CustomerArchiveBillingConfigurationsParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CustomerArchiveBillingConfigurationsResponse, - ) - - def list_billable_metrics( - self, - *, - customer_id: str, - include_archived: bool | Omit = omit, - limit: int | Omit = omit, - next_page: str | Omit = omit, - on_current_plan: bool | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[CustomerListBillableMetricsResponse]: - """Get all billable metrics available for a specific customer. - - Supports pagination - and filtering by current plan status or archived metrics. Use this endpoint to - see which metrics are being tracked for billing calculations for a given - customer. - - Args: - include_archived: If true, the list of returned metrics will include archived metrics - - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - on_current_plan: If true, the list of metrics will be filtered to just ones that are on the - customer's current plan - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - return self._get_api_list( - f"/v1/customers/{customer_id}/billable-metrics", - page=SyncCursorPage[CustomerListBillableMetricsResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "include_archived": include_archived, - "limit": limit, - "next_page": next_page, - "on_current_plan": on_current_plan, - }, - customer_list_billable_metrics_params.CustomerListBillableMetricsParams, - ), - ), - model=CustomerListBillableMetricsResponse, - ) - - def list_costs( - self, - *, - customer_id: str, - ending_before: Union[str, datetime], - starting_on: Union[str, datetime], - limit: int | Omit = omit, - next_page: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[CustomerListCostsResponse]: - """ - Fetch daily pending costs for the specified customer, broken down by credit type - and line items. Note: this is not supported for customers whose plan includes a - UNIQUE-type billable metric. This is a Plans (deprecated) endpoint. New clients - should implement using Contracts. - - Args: - ending_before: RFC 3339 timestamp (exclusive) - - starting_on: RFC 3339 timestamp (inclusive) - - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - return self._get_api_list( - f"/v1/customers/{customer_id}/costs", - page=SyncCursorPage[CustomerListCostsResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "ending_before": ending_before, - "starting_on": starting_on, - "limit": limit, - "next_page": next_page, - }, - customer_list_costs_params.CustomerListCostsParams, - ), - ), - model=CustomerListCostsResponse, - ) - - def preview_events( - self, - *, - customer_id: str, - events: Iterable[customer_preview_events_params.Event], - mode: Literal["replace", "merge"] | Omit = omit, - skip_zero_qty_line_items: bool | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CustomerPreviewEventsResponse: - """Preview how a set of events will affect a customer's invoices. - - Generates draft - invoices for a customer using their current contract configuration and the - provided events. This is useful for testing how new events will affect the - customer's invoices before they are actually processed. Customers on contracts - with SQL billable metrics are not supported. - - Args: - events: Array of usage events to include in the preview calculation. Must contain at - least one event in `merge` mode. - - mode: Controls how the provided events are combined with existing usage data. Use - `replace` to calculate the preview as if these are the only events for the - customer, ignoring all historical usage. Use `merge` to combine these events - with the customer's existing usage. Defaults to `replace`. - - skip_zero_qty_line_items: When `true`, line items with zero quantity are excluded from the response. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - return self._post( - f"/v1/customers/{customer_id}/previewEvents", - body=maybe_transform( - { - "events": events, - "mode": mode, - "skip_zero_qty_line_items": skip_zero_qty_line_items, - }, - customer_preview_events_params.CustomerPreviewEventsParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CustomerPreviewEventsResponse, - ) - - def retrieve_billing_configurations( - self, - *, - customer_id: str, - include_archived: bool | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CustomerRetrieveBillingConfigurationsResponse: - """Returns all billing configurations previously set for the customer. - - Use during - the contract provisioning process to fetch the - `billing_provider_configuration_id` needed to set the contract billing - configuration. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/getCustomerBillingProviderConfigurations", - body=maybe_transform( - { - "customer_id": customer_id, - "include_archived": include_archived, - }, - customer_retrieve_billing_configurations_params.CustomerRetrieveBillingConfigurationsParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CustomerRetrieveBillingConfigurationsResponse, - ) - - def set_billing_configurations( - self, - *, - data: Iterable[customer_set_billing_configurations_params.Data], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CustomerSetBillingConfigurationsResponse: - """Create a billing configuration for a customer. - - Once created, these - configurations are available to associate to a contract and dictates which - downstream system to collect payment in or send the invoice to. You can create - multiple configurations per customer. The configuration formats are distinct for - each downstream provider. - - ### Use this endpoint to: - - - Add the initial configuration to an existing customer. Once created, the - billing configuration can then be associated to the customer's contract. - - Add a new configuration to an existing customer. This might be used as part of - an upgrade or downgrade workflow where the customer was previously billed - through system A (e.g. Stripe) but will now be billed through system B (e.g. - AWS). Once created, the new configuration can then be associated to the - customer's contract. - - Multiple configurations can be added per destination. For example, you can - create two Stripe billing configurations for a Metronome customer that each - have a distinct `collection_method`. - - ### Delivery method options: - - - `direct_to_billing_provider`: Use when Metronome should send invoices directly - to the billing provider's API (e.g., Stripe, NetSuite). This is the most - common method for automated billing workflows. - - `tackle`: Use specifically for AWS Marketplace transactions that require - Tackle's co-selling platform for partner attribution and commission tracking. - - `aws_sqs`: Use when you want invoice data delivered to an AWS SQS queue for - custom processing before sending to your billing system. - - `aws_sns`: Use when you want invoice notifications published to an AWS SNS - topic for event-driven billing workflows. - - ### Key response fields: - - The id for the customer billing configuration. This id can be used to associate - the billing configuration to a contract. - - ### Usage guidelines: - - Must use the `delivery_method_id` if you have multiple Stripe accounts connected - to Metronome. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/setCustomerBillingProviderConfigurations", - body=maybe_transform( - {"data": data}, customer_set_billing_configurations_params.CustomerSetBillingConfigurationsParams - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CustomerSetBillingConfigurationsResponse, - ) - - def set_ingest_aliases( - self, - *, - customer_id: str, - ingest_aliases: SequenceNotStr[str], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """Sets the ingest aliases for a customer. - - Use this endpoint to associate a - Metronome customer with an internal ID for easier tracking between systems. - Ingest aliases can be used in the `customer_id` field when sending usage events - to Metronome. - - ### Usage guidelines: - - - This call is idempotent and fully replaces the set of ingest aliases for the - given customer. - - Switching an ingest alias from one customer to another will associate all - corresponding usage to the new customer. - - Use multiple ingest aliases to model child organizations within a single - Metronome customer. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._post( - f"/v1/customers/{customer_id}/setIngestAliases", - body=maybe_transform( - {"ingest_aliases": ingest_aliases}, customer_set_ingest_aliases_params.CustomerSetIngestAliasesParams - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def set_name( - self, - *, - customer_id: str, - name: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CustomerSetNameResponse: - """Updates the display name for a customer record. - - Use this to correct customer - names, update business names after rebranding, or maintain accurate customer - information for invoicing and reporting. Returns the updated customer object - with the new name applied immediately across all billing documents and - interfaces. - - Args: - name: The new name for the customer. This will be truncated to 160 characters if the - provided name is longer. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - return self._post( - f"/v1/customers/{customer_id}/setName", - body=maybe_transform({"name": name}, customer_set_name_params.CustomerSetNameParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CustomerSetNameResponse, - ) - - def update_config( - self, - *, - customer_id: str, - leave_stripe_invoices_in_draft: Optional[bool] | Omit = omit, - salesforce_account_id: Optional[str] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - Update configuration settings for a specific customer, such as external system - integrations (e.g., Salesforce account ID) and other customer-specific billing - parameters. Use this endpoint to modify customer configurations without - affecting core customer data like name or ingest aliases. - - Args: - leave_stripe_invoices_in_draft: Leave in draft or set to auto-advance on invoices sent to Stripe. Falls back to - the client-level config if unset, which defaults to true if unset. - - salesforce_account_id: The Salesforce account ID for the customer - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._post( - f"/v1/customers/{customer_id}/updateConfig", - body=maybe_transform( - { - "leave_stripe_invoices_in_draft": leave_stripe_invoices_in_draft, - "salesforce_account_id": salesforce_account_id, - }, - customer_update_config_params.CustomerUpdateConfigParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class AsyncCustomersResource(AsyncAPIResource): - @cached_property - def alerts(self) -> AsyncAlertsResource: - """ - [Alerts](https://docs.metronome.com/connecting-metronome/alerts/) monitor customer spending, balances, and other billing factors. Use these endpoints to create, retrieve, and archive customer alerts. To view sample alert payloads by alert type, navigate [here.](https://docs.metronome.com/manage-product-access/create-manage-alerts/#webhook-notifications) - """ - return AsyncAlertsResource(self._client) - - @cached_property - def plans(self) -> AsyncPlansResource: - """ - [Plans](https://docs.metronome.com/pricing-and-packaging/create-plans/) determine the base pricing for a customer. Use these endpoints to add a plan to a customer, end a customer plan, retrieve plans, and retrieve plan details. Create plans in the [Metronome app](https://app.metronome.com/plans). - """ - return AsyncPlansResource(self._client) - - @cached_property - def invoices(self) -> AsyncInvoicesResource: - """ - [Invoices](https://docs.metronome.com/invoicing/) reflect how much a customer spent during a period, which is the basis for billing. Metronome automatically generates invoices based upon your pricing, packaging, and usage events. Use these endpoints to retrieve invoices. - """ - return AsyncInvoicesResource(self._client) - - @cached_property - def billing_config(self) -> AsyncBillingConfigResource: - """ - [Customers](https://docs.metronome.com/provisioning/create-customers/) in Metronome represent your users for all billing and reporting. Use these endpoints to create, retrieve, update, and archive customers and their billing configuration. - """ - return AsyncBillingConfigResource(self._client) - - @cached_property - def commits(self) -> AsyncCommitsResource: - """Credits and commits are used to manage customer balances.""" - return AsyncCommitsResource(self._client) - - @cached_property - def credits(self) -> AsyncCreditsResource: - """Credits and commits are used to manage customer balances.""" - return AsyncCreditsResource(self._client) - - @cached_property - def named_schedules(self) -> AsyncNamedSchedulesResource: - """Named schedules are used for storing custom data that can change over time. - - Named schedules are often used in custom pricing logic. - """ - return AsyncNamedSchedulesResource(self._client) - - @cached_property - def with_raw_response(self) -> AsyncCustomersResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncCustomersResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncCustomersResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncCustomersResourceWithStreamingResponse(self) - - async def create( - self, - *, - name: str, - billing_config: customer_create_params.BillingConfig | Omit = omit, - custom_fields: Dict[str, str] | Omit = omit, - customer_billing_provider_configurations: Iterable[customer_create_params.CustomerBillingProviderConfiguration] - | Omit = omit, - customer_revenue_system_configurations: Iterable[customer_create_params.CustomerRevenueSystemConfiguration] - | Omit = omit, - external_id: str | Omit = omit, - ingest_aliases: SequenceNotStr[str] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CustomerCreateResponse: - """ - Create a new customer in Metronome and optionally the billing configuration - (recommended) which dictates where invoices for the customer will be sent or - where payment will be collected. - - ### Use this endpoint to: - - Execute your customer provisioning workflows for either PLG motions, where - customers originate in your platform, or SLG motions, where customers originate - in your sales system. - - ### Key response fields: - - This end-point returns the `customer_id` created by the request. This id can be - used to fetch relevant billing configurations and create contracts. - - ### Example workflow: - - - Generally, Metronome recommends first creating the customer in the downstream - payment / ERP system when payment method is collected and then creating the - customer in Metronome using the response (i.e. `customer_id`) from the - downstream system. If you do not create a billing configuration on customer - creation, you can add it later. - - Once a customer is created, you can then create a contract for the customer. - In the contract creation process, you will need to add the customer billing - configuration to the contract to ensure Metronome invoices the customer - correctly. This is because a customer can have multiple configurations. - - As part of the customer creation process, set the ingest alias for the - customer which will ensure usage is accurately mapped to the customer. Ingest - aliases can be added or changed after the creation process as well. - - ### Usage guidelines: - - For details on different billing configurations for different systems, review - the `/setCustomerBillingConfiguration` end-point. - - Args: - name: This will be truncated to 160 characters if the provided name is longer. - - custom_fields: Custom fields to be added eg. { "key1": "value1", "key2": "value2" } - - external_id: (deprecated, use ingest_aliases instead) an alias that can be used to refer to - this customer in usage events - - ingest_aliases: Aliases that can be used to refer to this customer in usage events - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/customers", - body=await async_maybe_transform( - { - "name": name, - "billing_config": billing_config, - "custom_fields": custom_fields, - "customer_billing_provider_configurations": customer_billing_provider_configurations, - "customer_revenue_system_configurations": customer_revenue_system_configurations, - "external_id": external_id, - "ingest_aliases": ingest_aliases, - }, - customer_create_params.CustomerCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CustomerCreateResponse, - ) - - async def retrieve( - self, - *, - customer_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CustomerRetrieveResponse: - """Get detailed information for a specific customer by their Metronome ID. - - Returns - customer profile data including name, creation date, ingest aliases, - configuration settings, and custom fields. Use this endpoint to fetch complete - customer details for billing operations or account management. - - Note: If searching for a customer billing configuration, use the - `/getCustomerBillingConfigurations` endpoint. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - return await self._get( - f"/v1/customers/{customer_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CustomerRetrieveResponse, - ) - - def list( - self, - *, - customer_ids: SequenceNotStr[str] | Omit = omit, - ingest_alias: str | Omit = omit, - limit: int | Omit = omit, - next_page: str | Omit = omit, - only_archived: bool | Omit = omit, - salesforce_account_ids: SequenceNotStr[str] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[CustomerDetail, AsyncCursorPage[CustomerDetail]]: - """Gets a paginated list of all customers in your Metronome account. - - Use this - endpoint to browse your customer base, implement customer search functionality, - or sync customer data with external systems. Returns customer details including - IDs, names, and configuration settings. Supports filtering and pagination - parameters for efficient data retrieval. - - Args: - customer_ids: Filter the customer list by customer_id. Up to 100 ids can be provided. - - ingest_alias: Filter the customer list by ingest_alias - - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - only_archived: Filter the customer list to only return archived customers. By default, only - active customers are returned. - - salesforce_account_ids: Filter the customer list by salesforce_account_id. Up to 100 ids can be - provided. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/customers", - page=AsyncCursorPage[CustomerDetail], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "customer_ids": customer_ids, - "ingest_alias": ingest_alias, - "limit": limit, - "next_page": next_page, - "only_archived": only_archived, - "salesforce_account_ids": salesforce_account_ids, - }, - customer_list_params.CustomerListParams, - ), - ), - model=CustomerDetail, - ) - - async def archive( - self, - *, - id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CustomerArchiveResponse: - """Use this endpoint to archive a customer while preserving auditability. - - Archiving - a customer will automatically archive all contracts as of the current date and - void all corresponding invoices. Use this endpoint if a customer is onboarded by - mistake. - - ### Usage guidelines: - - - Once a customer is archived, it cannot be unarchived. - - Archived customers can still be viewed through the API or the UI for audit - purposes. - - Ingest aliases remain idempotent for archived customers. In order to reuse an - ingest alias, first remove the ingest alias from the customer prior to - archiving. - - Any notifications associated with the customer will no longer be triggered. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/customers/archive", - body=await async_maybe_transform({"id": id}, customer_archive_params.CustomerArchiveParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CustomerArchiveResponse, - ) - - async def archive_billing_configurations( - self, - *, - customer_billing_provider_configuration_ids: SequenceNotStr[str], - customer_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CustomerArchiveBillingConfigurationsResponse: - """ - Deprecate an existing billing configuration for a customer to handle churn or - billing and collection preference changes. Archiving a billing configuration - takes effect immediately. If there are active contracts using the configuration, - Metronome will archive the configuration on the contract and immediately stop - metering to downstream systems. - - ### Use this endpoint to: - - - Remove billing provider customer data and configurations when no longer needed - - Clean up test or deprecated billing provider configurations - - Free up uniqueness keys for reuse with new billing provider configurations - - Disable threshold recharge configurations associated with archived billing - providers - - ### Key response fields: - - A successful response returns: - - - `success`: Boolean indicating the operation completed successfully - - `error`: Null on success, error message on failure - - ### Usage guidelines: - - - Archiving a contract configuration during a grace period will result in the - invoice not being sent to the customer - - Automatically disables both spend-based and credit-based threshold recharge - configurations for contracts using the archived billing provider - - You can archive multiple configurations for a single customer in a single - request, but any validation failures for an individual configuration will - prevent the entire operation from succeeding - - Args: - customer_billing_provider_configuration_ids: Array of billing provider configuration IDs to archive - - customer_id: The customer ID the billing provider configurations belong to - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/archiveCustomerBillingProviderConfigurations", - body=await async_maybe_transform( - { - "customer_billing_provider_configuration_ids": customer_billing_provider_configuration_ids, - "customer_id": customer_id, - }, - customer_archive_billing_configurations_params.CustomerArchiveBillingConfigurationsParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CustomerArchiveBillingConfigurationsResponse, - ) - - def list_billable_metrics( - self, - *, - customer_id: str, - include_archived: bool | Omit = omit, - limit: int | Omit = omit, - next_page: str | Omit = omit, - on_current_plan: bool | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[CustomerListBillableMetricsResponse, AsyncCursorPage[CustomerListBillableMetricsResponse]]: - """Get all billable metrics available for a specific customer. - - Supports pagination - and filtering by current plan status or archived metrics. Use this endpoint to - see which metrics are being tracked for billing calculations for a given - customer. - - Args: - include_archived: If true, the list of returned metrics will include archived metrics - - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - on_current_plan: If true, the list of metrics will be filtered to just ones that are on the - customer's current plan - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - return self._get_api_list( - f"/v1/customers/{customer_id}/billable-metrics", - page=AsyncCursorPage[CustomerListBillableMetricsResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "include_archived": include_archived, - "limit": limit, - "next_page": next_page, - "on_current_plan": on_current_plan, - }, - customer_list_billable_metrics_params.CustomerListBillableMetricsParams, - ), - ), - model=CustomerListBillableMetricsResponse, - ) - - def list_costs( - self, - *, - customer_id: str, - ending_before: Union[str, datetime], - starting_on: Union[str, datetime], - limit: int | Omit = omit, - next_page: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[CustomerListCostsResponse, AsyncCursorPage[CustomerListCostsResponse]]: - """ - Fetch daily pending costs for the specified customer, broken down by credit type - and line items. Note: this is not supported for customers whose plan includes a - UNIQUE-type billable metric. This is a Plans (deprecated) endpoint. New clients - should implement using Contracts. - - Args: - ending_before: RFC 3339 timestamp (exclusive) - - starting_on: RFC 3339 timestamp (inclusive) - - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - return self._get_api_list( - f"/v1/customers/{customer_id}/costs", - page=AsyncCursorPage[CustomerListCostsResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "ending_before": ending_before, - "starting_on": starting_on, - "limit": limit, - "next_page": next_page, - }, - customer_list_costs_params.CustomerListCostsParams, - ), - ), - model=CustomerListCostsResponse, - ) - - async def preview_events( - self, - *, - customer_id: str, - events: Iterable[customer_preview_events_params.Event], - mode: Literal["replace", "merge"] | Omit = omit, - skip_zero_qty_line_items: bool | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CustomerPreviewEventsResponse: - """Preview how a set of events will affect a customer's invoices. - - Generates draft - invoices for a customer using their current contract configuration and the - provided events. This is useful for testing how new events will affect the - customer's invoices before they are actually processed. Customers on contracts - with SQL billable metrics are not supported. - - Args: - events: Array of usage events to include in the preview calculation. Must contain at - least one event in `merge` mode. - - mode: Controls how the provided events are combined with existing usage data. Use - `replace` to calculate the preview as if these are the only events for the - customer, ignoring all historical usage. Use `merge` to combine these events - with the customer's existing usage. Defaults to `replace`. - - skip_zero_qty_line_items: When `true`, line items with zero quantity are excluded from the response. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - return await self._post( - f"/v1/customers/{customer_id}/previewEvents", - body=await async_maybe_transform( - { - "events": events, - "mode": mode, - "skip_zero_qty_line_items": skip_zero_qty_line_items, - }, - customer_preview_events_params.CustomerPreviewEventsParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CustomerPreviewEventsResponse, - ) - - async def retrieve_billing_configurations( - self, - *, - customer_id: str, - include_archived: bool | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CustomerRetrieveBillingConfigurationsResponse: - """Returns all billing configurations previously set for the customer. - - Use during - the contract provisioning process to fetch the - `billing_provider_configuration_id` needed to set the contract billing - configuration. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/getCustomerBillingProviderConfigurations", - body=await async_maybe_transform( - { - "customer_id": customer_id, - "include_archived": include_archived, - }, - customer_retrieve_billing_configurations_params.CustomerRetrieveBillingConfigurationsParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CustomerRetrieveBillingConfigurationsResponse, - ) - - async def set_billing_configurations( - self, - *, - data: Iterable[customer_set_billing_configurations_params.Data], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CustomerSetBillingConfigurationsResponse: - """Create a billing configuration for a customer. - - Once created, these - configurations are available to associate to a contract and dictates which - downstream system to collect payment in or send the invoice to. You can create - multiple configurations per customer. The configuration formats are distinct for - each downstream provider. - - ### Use this endpoint to: - - - Add the initial configuration to an existing customer. Once created, the - billing configuration can then be associated to the customer's contract. - - Add a new configuration to an existing customer. This might be used as part of - an upgrade or downgrade workflow where the customer was previously billed - through system A (e.g. Stripe) but will now be billed through system B (e.g. - AWS). Once created, the new configuration can then be associated to the - customer's contract. - - Multiple configurations can be added per destination. For example, you can - create two Stripe billing configurations for a Metronome customer that each - have a distinct `collection_method`. - - ### Delivery method options: - - - `direct_to_billing_provider`: Use when Metronome should send invoices directly - to the billing provider's API (e.g., Stripe, NetSuite). This is the most - common method for automated billing workflows. - - `tackle`: Use specifically for AWS Marketplace transactions that require - Tackle's co-selling platform for partner attribution and commission tracking. - - `aws_sqs`: Use when you want invoice data delivered to an AWS SQS queue for - custom processing before sending to your billing system. - - `aws_sns`: Use when you want invoice notifications published to an AWS SNS - topic for event-driven billing workflows. - - ### Key response fields: - - The id for the customer billing configuration. This id can be used to associate - the billing configuration to a contract. - - ### Usage guidelines: - - Must use the `delivery_method_id` if you have multiple Stripe accounts connected - to Metronome. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/setCustomerBillingProviderConfigurations", - body=await async_maybe_transform( - {"data": data}, customer_set_billing_configurations_params.CustomerSetBillingConfigurationsParams - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CustomerSetBillingConfigurationsResponse, - ) - - async def set_ingest_aliases( - self, - *, - customer_id: str, - ingest_aliases: SequenceNotStr[str], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """Sets the ingest aliases for a customer. - - Use this endpoint to associate a - Metronome customer with an internal ID for easier tracking between systems. - Ingest aliases can be used in the `customer_id` field when sending usage events - to Metronome. - - ### Usage guidelines: - - - This call is idempotent and fully replaces the set of ingest aliases for the - given customer. - - Switching an ingest alias from one customer to another will associate all - corresponding usage to the new customer. - - Use multiple ingest aliases to model child organizations within a single - Metronome customer. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._post( - f"/v1/customers/{customer_id}/setIngestAliases", - body=await async_maybe_transform( - {"ingest_aliases": ingest_aliases}, customer_set_ingest_aliases_params.CustomerSetIngestAliasesParams - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - async def set_name( - self, - *, - customer_id: str, - name: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> CustomerSetNameResponse: - """Updates the display name for a customer record. - - Use this to correct customer - names, update business names after rebranding, or maintain accurate customer - information for invoicing and reporting. Returns the updated customer object - with the new name applied immediately across all billing documents and - interfaces. - - Args: - name: The new name for the customer. This will be truncated to 160 characters if the - provided name is longer. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - return await self._post( - f"/v1/customers/{customer_id}/setName", - body=await async_maybe_transform({"name": name}, customer_set_name_params.CustomerSetNameParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=CustomerSetNameResponse, - ) - - async def update_config( - self, - *, - customer_id: str, - leave_stripe_invoices_in_draft: Optional[bool] | Omit = omit, - salesforce_account_id: Optional[str] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - Update configuration settings for a specific customer, such as external system - integrations (e.g., Salesforce account ID) and other customer-specific billing - parameters. Use this endpoint to modify customer configurations without - affecting core customer data like name or ingest aliases. - - Args: - leave_stripe_invoices_in_draft: Leave in draft or set to auto-advance on invoices sent to Stripe. Falls back to - the client-level config if unset, which defaults to true if unset. - - salesforce_account_id: The Salesforce account ID for the customer - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._post( - f"/v1/customers/{customer_id}/updateConfig", - body=await async_maybe_transform( - { - "leave_stripe_invoices_in_draft": leave_stripe_invoices_in_draft, - "salesforce_account_id": salesforce_account_id, - }, - customer_update_config_params.CustomerUpdateConfigParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class CustomersResourceWithRawResponse: - def __init__(self, customers: CustomersResource) -> None: - self._customers = customers - - self.create = to_raw_response_wrapper( - customers.create, - ) - self.retrieve = to_raw_response_wrapper( - customers.retrieve, - ) - self.list = to_raw_response_wrapper( - customers.list, - ) - self.archive = to_raw_response_wrapper( - customers.archive, - ) - self.archive_billing_configurations = to_raw_response_wrapper( - customers.archive_billing_configurations, - ) - self.list_billable_metrics = to_raw_response_wrapper( - customers.list_billable_metrics, - ) - self.list_costs = to_raw_response_wrapper( - customers.list_costs, - ) - self.preview_events = to_raw_response_wrapper( - customers.preview_events, - ) - self.retrieve_billing_configurations = to_raw_response_wrapper( - customers.retrieve_billing_configurations, - ) - self.set_billing_configurations = to_raw_response_wrapper( - customers.set_billing_configurations, - ) - self.set_ingest_aliases = to_raw_response_wrapper( - customers.set_ingest_aliases, - ) - self.set_name = to_raw_response_wrapper( - customers.set_name, - ) - self.update_config = to_raw_response_wrapper( - customers.update_config, - ) - - @cached_property - def alerts(self) -> AlertsResourceWithRawResponse: - """ - [Alerts](https://docs.metronome.com/connecting-metronome/alerts/) monitor customer spending, balances, and other billing factors. Use these endpoints to create, retrieve, and archive customer alerts. To view sample alert payloads by alert type, navigate [here.](https://docs.metronome.com/manage-product-access/create-manage-alerts/#webhook-notifications) - """ - return AlertsResourceWithRawResponse(self._customers.alerts) - - @cached_property - def plans(self) -> PlansResourceWithRawResponse: - """ - [Plans](https://docs.metronome.com/pricing-and-packaging/create-plans/) determine the base pricing for a customer. Use these endpoints to add a plan to a customer, end a customer plan, retrieve plans, and retrieve plan details. Create plans in the [Metronome app](https://app.metronome.com/plans). - """ - return PlansResourceWithRawResponse(self._customers.plans) - - @cached_property - def invoices(self) -> InvoicesResourceWithRawResponse: - """ - [Invoices](https://docs.metronome.com/invoicing/) reflect how much a customer spent during a period, which is the basis for billing. Metronome automatically generates invoices based upon your pricing, packaging, and usage events. Use these endpoints to retrieve invoices. - """ - return InvoicesResourceWithRawResponse(self._customers.invoices) - - @cached_property - def billing_config(self) -> BillingConfigResourceWithRawResponse: - """ - [Customers](https://docs.metronome.com/provisioning/create-customers/) in Metronome represent your users for all billing and reporting. Use these endpoints to create, retrieve, update, and archive customers and their billing configuration. - """ - return BillingConfigResourceWithRawResponse(self._customers.billing_config) - - @cached_property - def commits(self) -> CommitsResourceWithRawResponse: - """Credits and commits are used to manage customer balances.""" - return CommitsResourceWithRawResponse(self._customers.commits) - - @cached_property - def credits(self) -> CreditsResourceWithRawResponse: - """Credits and commits are used to manage customer balances.""" - return CreditsResourceWithRawResponse(self._customers.credits) - - @cached_property - def named_schedules(self) -> NamedSchedulesResourceWithRawResponse: - """Named schedules are used for storing custom data that can change over time. - - Named schedules are often used in custom pricing logic. - """ - return NamedSchedulesResourceWithRawResponse(self._customers.named_schedules) - - -class AsyncCustomersResourceWithRawResponse: - def __init__(self, customers: AsyncCustomersResource) -> None: - self._customers = customers - - self.create = async_to_raw_response_wrapper( - customers.create, - ) - self.retrieve = async_to_raw_response_wrapper( - customers.retrieve, - ) - self.list = async_to_raw_response_wrapper( - customers.list, - ) - self.archive = async_to_raw_response_wrapper( - customers.archive, - ) - self.archive_billing_configurations = async_to_raw_response_wrapper( - customers.archive_billing_configurations, - ) - self.list_billable_metrics = async_to_raw_response_wrapper( - customers.list_billable_metrics, - ) - self.list_costs = async_to_raw_response_wrapper( - customers.list_costs, - ) - self.preview_events = async_to_raw_response_wrapper( - customers.preview_events, - ) - self.retrieve_billing_configurations = async_to_raw_response_wrapper( - customers.retrieve_billing_configurations, - ) - self.set_billing_configurations = async_to_raw_response_wrapper( - customers.set_billing_configurations, - ) - self.set_ingest_aliases = async_to_raw_response_wrapper( - customers.set_ingest_aliases, - ) - self.set_name = async_to_raw_response_wrapper( - customers.set_name, - ) - self.update_config = async_to_raw_response_wrapper( - customers.update_config, - ) - - @cached_property - def alerts(self) -> AsyncAlertsResourceWithRawResponse: - """ - [Alerts](https://docs.metronome.com/connecting-metronome/alerts/) monitor customer spending, balances, and other billing factors. Use these endpoints to create, retrieve, and archive customer alerts. To view sample alert payloads by alert type, navigate [here.](https://docs.metronome.com/manage-product-access/create-manage-alerts/#webhook-notifications) - """ - return AsyncAlertsResourceWithRawResponse(self._customers.alerts) - - @cached_property - def plans(self) -> AsyncPlansResourceWithRawResponse: - """ - [Plans](https://docs.metronome.com/pricing-and-packaging/create-plans/) determine the base pricing for a customer. Use these endpoints to add a plan to a customer, end a customer plan, retrieve plans, and retrieve plan details. Create plans in the [Metronome app](https://app.metronome.com/plans). - """ - return AsyncPlansResourceWithRawResponse(self._customers.plans) - - @cached_property - def invoices(self) -> AsyncInvoicesResourceWithRawResponse: - """ - [Invoices](https://docs.metronome.com/invoicing/) reflect how much a customer spent during a period, which is the basis for billing. Metronome automatically generates invoices based upon your pricing, packaging, and usage events. Use these endpoints to retrieve invoices. - """ - return AsyncInvoicesResourceWithRawResponse(self._customers.invoices) - - @cached_property - def billing_config(self) -> AsyncBillingConfigResourceWithRawResponse: - """ - [Customers](https://docs.metronome.com/provisioning/create-customers/) in Metronome represent your users for all billing and reporting. Use these endpoints to create, retrieve, update, and archive customers and their billing configuration. - """ - return AsyncBillingConfigResourceWithRawResponse(self._customers.billing_config) - - @cached_property - def commits(self) -> AsyncCommitsResourceWithRawResponse: - """Credits and commits are used to manage customer balances.""" - return AsyncCommitsResourceWithRawResponse(self._customers.commits) - - @cached_property - def credits(self) -> AsyncCreditsResourceWithRawResponse: - """Credits and commits are used to manage customer balances.""" - return AsyncCreditsResourceWithRawResponse(self._customers.credits) - - @cached_property - def named_schedules(self) -> AsyncNamedSchedulesResourceWithRawResponse: - """Named schedules are used for storing custom data that can change over time. - - Named schedules are often used in custom pricing logic. - """ - return AsyncNamedSchedulesResourceWithRawResponse(self._customers.named_schedules) - - -class CustomersResourceWithStreamingResponse: - def __init__(self, customers: CustomersResource) -> None: - self._customers = customers - - self.create = to_streamed_response_wrapper( - customers.create, - ) - self.retrieve = to_streamed_response_wrapper( - customers.retrieve, - ) - self.list = to_streamed_response_wrapper( - customers.list, - ) - self.archive = to_streamed_response_wrapper( - customers.archive, - ) - self.archive_billing_configurations = to_streamed_response_wrapper( - customers.archive_billing_configurations, - ) - self.list_billable_metrics = to_streamed_response_wrapper( - customers.list_billable_metrics, - ) - self.list_costs = to_streamed_response_wrapper( - customers.list_costs, - ) - self.preview_events = to_streamed_response_wrapper( - customers.preview_events, - ) - self.retrieve_billing_configurations = to_streamed_response_wrapper( - customers.retrieve_billing_configurations, - ) - self.set_billing_configurations = to_streamed_response_wrapper( - customers.set_billing_configurations, - ) - self.set_ingest_aliases = to_streamed_response_wrapper( - customers.set_ingest_aliases, - ) - self.set_name = to_streamed_response_wrapper( - customers.set_name, - ) - self.update_config = to_streamed_response_wrapper( - customers.update_config, - ) - - @cached_property - def alerts(self) -> AlertsResourceWithStreamingResponse: - """ - [Alerts](https://docs.metronome.com/connecting-metronome/alerts/) monitor customer spending, balances, and other billing factors. Use these endpoints to create, retrieve, and archive customer alerts. To view sample alert payloads by alert type, navigate [here.](https://docs.metronome.com/manage-product-access/create-manage-alerts/#webhook-notifications) - """ - return AlertsResourceWithStreamingResponse(self._customers.alerts) - - @cached_property - def plans(self) -> PlansResourceWithStreamingResponse: - """ - [Plans](https://docs.metronome.com/pricing-and-packaging/create-plans/) determine the base pricing for a customer. Use these endpoints to add a plan to a customer, end a customer plan, retrieve plans, and retrieve plan details. Create plans in the [Metronome app](https://app.metronome.com/plans). - """ - return PlansResourceWithStreamingResponse(self._customers.plans) - - @cached_property - def invoices(self) -> InvoicesResourceWithStreamingResponse: - """ - [Invoices](https://docs.metronome.com/invoicing/) reflect how much a customer spent during a period, which is the basis for billing. Metronome automatically generates invoices based upon your pricing, packaging, and usage events. Use these endpoints to retrieve invoices. - """ - return InvoicesResourceWithStreamingResponse(self._customers.invoices) - - @cached_property - def billing_config(self) -> BillingConfigResourceWithStreamingResponse: - """ - [Customers](https://docs.metronome.com/provisioning/create-customers/) in Metronome represent your users for all billing and reporting. Use these endpoints to create, retrieve, update, and archive customers and their billing configuration. - """ - return BillingConfigResourceWithStreamingResponse(self._customers.billing_config) - - @cached_property - def commits(self) -> CommitsResourceWithStreamingResponse: - """Credits and commits are used to manage customer balances.""" - return CommitsResourceWithStreamingResponse(self._customers.commits) - - @cached_property - def credits(self) -> CreditsResourceWithStreamingResponse: - """Credits and commits are used to manage customer balances.""" - return CreditsResourceWithStreamingResponse(self._customers.credits) - - @cached_property - def named_schedules(self) -> NamedSchedulesResourceWithStreamingResponse: - """Named schedules are used for storing custom data that can change over time. - - Named schedules are often used in custom pricing logic. - """ - return NamedSchedulesResourceWithStreamingResponse(self._customers.named_schedules) - - -class AsyncCustomersResourceWithStreamingResponse: - def __init__(self, customers: AsyncCustomersResource) -> None: - self._customers = customers - - self.create = async_to_streamed_response_wrapper( - customers.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - customers.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - customers.list, - ) - self.archive = async_to_streamed_response_wrapper( - customers.archive, - ) - self.archive_billing_configurations = async_to_streamed_response_wrapper( - customers.archive_billing_configurations, - ) - self.list_billable_metrics = async_to_streamed_response_wrapper( - customers.list_billable_metrics, - ) - self.list_costs = async_to_streamed_response_wrapper( - customers.list_costs, - ) - self.preview_events = async_to_streamed_response_wrapper( - customers.preview_events, - ) - self.retrieve_billing_configurations = async_to_streamed_response_wrapper( - customers.retrieve_billing_configurations, - ) - self.set_billing_configurations = async_to_streamed_response_wrapper( - customers.set_billing_configurations, - ) - self.set_ingest_aliases = async_to_streamed_response_wrapper( - customers.set_ingest_aliases, - ) - self.set_name = async_to_streamed_response_wrapper( - customers.set_name, - ) - self.update_config = async_to_streamed_response_wrapper( - customers.update_config, - ) - - @cached_property - def alerts(self) -> AsyncAlertsResourceWithStreamingResponse: - """ - [Alerts](https://docs.metronome.com/connecting-metronome/alerts/) monitor customer spending, balances, and other billing factors. Use these endpoints to create, retrieve, and archive customer alerts. To view sample alert payloads by alert type, navigate [here.](https://docs.metronome.com/manage-product-access/create-manage-alerts/#webhook-notifications) - """ - return AsyncAlertsResourceWithStreamingResponse(self._customers.alerts) - - @cached_property - def plans(self) -> AsyncPlansResourceWithStreamingResponse: - """ - [Plans](https://docs.metronome.com/pricing-and-packaging/create-plans/) determine the base pricing for a customer. Use these endpoints to add a plan to a customer, end a customer plan, retrieve plans, and retrieve plan details. Create plans in the [Metronome app](https://app.metronome.com/plans). - """ - return AsyncPlansResourceWithStreamingResponse(self._customers.plans) - - @cached_property - def invoices(self) -> AsyncInvoicesResourceWithStreamingResponse: - """ - [Invoices](https://docs.metronome.com/invoicing/) reflect how much a customer spent during a period, which is the basis for billing. Metronome automatically generates invoices based upon your pricing, packaging, and usage events. Use these endpoints to retrieve invoices. - """ - return AsyncInvoicesResourceWithStreamingResponse(self._customers.invoices) - - @cached_property - def billing_config(self) -> AsyncBillingConfigResourceWithStreamingResponse: - """ - [Customers](https://docs.metronome.com/provisioning/create-customers/) in Metronome represent your users for all billing and reporting. Use these endpoints to create, retrieve, update, and archive customers and their billing configuration. - """ - return AsyncBillingConfigResourceWithStreamingResponse(self._customers.billing_config) - - @cached_property - def commits(self) -> AsyncCommitsResourceWithStreamingResponse: - """Credits and commits are used to manage customer balances.""" - return AsyncCommitsResourceWithStreamingResponse(self._customers.commits) - - @cached_property - def credits(self) -> AsyncCreditsResourceWithStreamingResponse: - """Credits and commits are used to manage customer balances.""" - return AsyncCreditsResourceWithStreamingResponse(self._customers.credits) - - @cached_property - def named_schedules(self) -> AsyncNamedSchedulesResourceWithStreamingResponse: - """Named schedules are used for storing custom data that can change over time. - - Named schedules are often used in custom pricing logic. - """ - return AsyncNamedSchedulesResourceWithStreamingResponse(self._customers.named_schedules) diff --git a/src/metronome/resources/v1/customers/invoices.py b/src/metronome/resources/v1/customers/invoices.py deleted file mode 100644 index 89c14adc4..000000000 --- a/src/metronome/resources/v1/customers/invoices.py +++ /dev/null @@ -1,1088 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Literal - -import httpx - -from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import ( - BinaryAPIResponse, - AsyncBinaryAPIResponse, - StreamedBinaryAPIResponse, - AsyncStreamedBinaryAPIResponse, - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - to_custom_raw_response_wrapper, - async_to_streamed_response_wrapper, - to_custom_streamed_response_wrapper, - async_to_custom_raw_response_wrapper, - async_to_custom_streamed_response_wrapper, -) -from ....pagination import SyncCursorPage, AsyncCursorPage -from ...._base_client import AsyncPaginator, make_request_options -from ....types.v1.customers import ( - invoice_list_params, - invoice_retrieve_params, - invoice_add_charge_params, - invoice_list_breakdowns_params, -) -from ....types.v1.customers.invoice import Invoice -from ....types.v1.customers.invoice_retrieve_response import InvoiceRetrieveResponse -from ....types.v1.customers.invoice_add_charge_response import InvoiceAddChargeResponse -from ....types.v1.customers.invoice_list_breakdowns_response import InvoiceListBreakdownsResponse - -__all__ = ["InvoicesResource", "AsyncInvoicesResource"] - - -class InvoicesResource(SyncAPIResource): - """ - [Invoices](https://docs.metronome.com/invoicing/) reflect how much a customer spent during a period, which is the basis for billing. Metronome automatically generates invoices based upon your pricing, packaging, and usage events. Use these endpoints to retrieve invoices. - """ - - @cached_property - def with_raw_response(self) -> InvoicesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return InvoicesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> InvoicesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return InvoicesResourceWithStreamingResponse(self) - - def retrieve( - self, - *, - customer_id: str, - invoice_id: str, - skip_zero_qty_line_items: bool | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> InvoiceRetrieveResponse: - """ - Retrieve detailed information for a specific invoice by its unique identifier. - This endpoint returns comprehensive invoice data including line items, applied - credits, totals, and billing period details for both finalized and draft - invoices. - - ### Use this endpoint to: - - - Display historical invoice details in customer-facing dashboards or billing - portals. - - Retrieve current month draft invoices to show customers their month-to-date - spend. - - Access finalized invoices for historical billing records and payment - reconciliation. - - Validate customer pricing and credit applications for customer support - queries. - - ### Key response fields: - - Invoice status (DRAFT, FINALIZED, VOID) Billing period start and end dates Total - amount and amount due after credits Detailed line items broken down by: - - - Customer and contract information - - Invoice line item type - - Product/service name and ID - - Quantity consumed - - Unit and total price - - Time period for usage-based charges - - Applied credits or prepaid commitments - - ### Usage guidelines: - - - Draft invoices update in real-time as usage is reported and may change before - finalization - - The response includes both usage-based line items (e.g., API calls, data - processed) and scheduled charges (e.g., monthly subscriptions, commitment - fees) - - Credit and commitment applications are shown as separate line items with - negative amounts - - For voided invoices, the response will indicate VOID status but retain all - original line item details - - Args: - skip_zero_qty_line_items: If set, all zero quantity line items will be filtered out of the response - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - if not invoice_id: - raise ValueError(f"Expected a non-empty value for `invoice_id` but received {invoice_id!r}") - return self._get( - f"/v1/customers/{customer_id}/invoices/{invoice_id}", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - {"skip_zero_qty_line_items": skip_zero_qty_line_items}, - invoice_retrieve_params.InvoiceRetrieveParams, - ), - ), - cast_to=InvoiceRetrieveResponse, - ) - - def list( - self, - *, - customer_id: str, - credit_type_id: str | Omit = omit, - ending_before: Union[str, datetime] | Omit = omit, - limit: int | Omit = omit, - next_page: str | Omit = omit, - skip_zero_qty_line_items: bool | Omit = omit, - sort: Literal["date_asc", "date_desc"] | Omit = omit, - starting_on: Union[str, datetime] | Omit = omit, - status: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[Invoice]: - """ - Retrieves a paginated list of invoices for a specific customer, with flexible - filtering options to narrow results by status, date range, credit type, and - more. This endpoint provides a comprehensive view of a customer's billing - history and current charges, supporting both real-time billing dashboards and - historical reporting needs. - - ### Use this endpoint to: - - - Display historical invoice details in customer-facing dashboards or billing - portals. - - Retrieve current month draft invoices to show customers their month-to-date - spend. - - Access finalized invoices for historical billing records and payment - reconciliation. - - Validate customer pricing and credit applications for customer support - queries. - - Generate financial reports by filtering invoices within specific date ranges - - ### Key response fields: - - Array of invoice objects containing: - - - Invoice ID and status (DRAFT, FINALIZED, VOID) - - Invoice type (USAGE, SCHEDULED) - - Billing period start and end dates - - Issue date and due date - - Total amount, subtotal, and amount due - - Applied credits summary - - Contract ID reference - - External billing provider status (if integrated with Stripe, etc.) - - Pagination metadata `next_page` cursor - - ### Usage guidelines: - - - The endpoint returns invoice summaries; use the Get Invoice endpoint for - detailed line items - - Draft invoices are continuously updated as new usage is reported and will show - real-time spend - - Results are ordered by creation date descending by default (newest first) - - When filtering by date range, the filter applies to the billing period, not - the issue date - - For customers with many invoices, implement pagination to ensure all results - are retrieved External billing provider statuses (like Stripe payment status) - are included when applicable - - Voided invoices are included in results by default unless filtered out by - status - - Args: - credit_type_id: Only return invoices for the specified credit type - - ending_before: RFC 3339 timestamp (exclusive). Invoices will only be returned for billing - periods that end before this time. - - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - skip_zero_qty_line_items: If set, all zero quantity line items will be filtered out of the response - - sort: Invoice sort order by issued_at, e.g. date_asc or date_desc. Defaults to - date_asc. - - starting_on: RFC 3339 timestamp (inclusive). Invoices will only be returned for billing - periods that start at or after this time. - - status: Invoice status, e.g. DRAFT, FINALIZED, or VOID - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - return self._get_api_list( - f"/v1/customers/{customer_id}/invoices", - page=SyncCursorPage[Invoice], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "credit_type_id": credit_type_id, - "ending_before": ending_before, - "limit": limit, - "next_page": next_page, - "skip_zero_qty_line_items": skip_zero_qty_line_items, - "sort": sort, - "starting_on": starting_on, - "status": status, - }, - invoice_list_params.InvoiceListParams, - ), - ), - model=Invoice, - ) - - def add_charge( - self, - *, - customer_id: str, - charge_id: str, - customer_plan_id: str, - description: str, - invoice_start_timestamp: Union[str, datetime], - price: float, - quantity: float, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> InvoiceAddChargeResponse: - """Add a one time charge to the specified invoice. - - This is a Plans (deprecated) - endpoint. New clients should implement using Contracts. - - Args: - charge_id: The Metronome ID of the charge to add to the invoice. Note that the charge must - be on a product that is not on the current plan, and the product must have only - fixed charges. - - customer_plan_id: The Metronome ID of the customer plan to add the charge to. - - invoice_start_timestamp: The start_timestamp of the invoice to add the charge to. - - price: The price of the charge. This price will match the currency on the invoice, e.g. - USD cents. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - return self._post( - f"/v1/customers/{customer_id}/addCharge", - body=maybe_transform( - { - "charge_id": charge_id, - "customer_plan_id": customer_plan_id, - "description": description, - "invoice_start_timestamp": invoice_start_timestamp, - "price": price, - "quantity": quantity, - }, - invoice_add_charge_params.InvoiceAddChargeParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=InvoiceAddChargeResponse, - ) - - def list_breakdowns( - self, - *, - customer_id: str, - ending_before: Union[str, datetime], - starting_on: Union[str, datetime], - credit_type_id: str | Omit = omit, - limit: int | Omit = omit, - next_page: str | Omit = omit, - skip_zero_qty_line_items: bool | Omit = omit, - sort: Literal["date_asc", "date_desc"] | Omit = omit, - status: str | Omit = omit, - window_size: Literal["HOUR", "DAY"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[InvoiceListBreakdownsResponse]: - """ - Retrieve granular time-series breakdowns of invoice data at hourly or daily - intervals. This endpoint transforms standard invoices into detailed timelines, - enabling you to track usage patterns, identify consumption spikes, and provide - customers with transparency into their billing details throughout the billing - period. - - ### Use this endpoint to: - - - Build usage analytics dashboards showing daily or hourly consumption trends - - Identify peak usage periods for capacity planning and cost optimization - - Generate detailed billing reports for finance teams and customer success - - Troubleshoot billing disputes by examining usage patterns at specific times - - Power real-time cost monitoring and alerting systems - - ### Key response fields: - - An array of BreakdownInvoice objects, each containing: - - - All standard invoice fields (ID, customer, commit, line items, totals, status) - - Line items with quantities and costs for that specific period - - `breakdown_start_timestamp`: Start of the specific time window - - `breakdown_end_timestamp`: End of the specific time window - - `next_page`: Pagination cursor for large result sets - - ### Usage guidelines: - - - Time granularity: Set `window_size` to hour or day based on your analysis - needs - - Response limits: Daily breakdowns return up to 35 days; hourly breakdowns - return up to 24 hours per request - - Date filtering: Use `starting_on` and `ending_before` to focus on specific - periods - - Performance: For large date ranges, use pagination to retrieve all data - efficiently - - Backdated usage: If usage events arrive after invoice finalization, breakdowns - will reflect the updated usage - - Zero quantity filtering: Use `skip_zero_qty_line_items=true` to exclude - periods with no usage - - Args: - ending_before: RFC 3339 timestamp. Breakdowns will only be returned for time windows that end - on or before this time. - - starting_on: RFC 3339 timestamp. Breakdowns will only be returned for time windows that start - on or after this time. - - credit_type_id: Only return invoices for the specified credit type - - limit: Max number of results that should be returned. For daily breakdowns, the - response can return up to 35 days worth of breakdowns. For hourly breakdowns, - the response can return up to 24 hours. If there are more results, a cursor to - the next page is returned. - - next_page: Cursor that indicates where the next page of results should start. - - skip_zero_qty_line_items: If set, all zero quantity line items will be filtered out of the response - - sort: Invoice sort order by issued_at, e.g. date_asc or date_desc. Defaults to - date_asc. - - status: Invoice status, e.g. DRAFT or FINALIZED - - window_size: The granularity of the breakdowns to return. Defaults to day. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - return self._get_api_list( - f"/v1/customers/{customer_id}/invoices/breakdowns", - page=SyncCursorPage[InvoiceListBreakdownsResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "ending_before": ending_before, - "starting_on": starting_on, - "credit_type_id": credit_type_id, - "limit": limit, - "next_page": next_page, - "skip_zero_qty_line_items": skip_zero_qty_line_items, - "sort": sort, - "status": status, - "window_size": window_size, - }, - invoice_list_breakdowns_params.InvoiceListBreakdownsParams, - ), - ), - model=InvoiceListBreakdownsResponse, - ) - - def retrieve_pdf( - self, - *, - customer_id: str, - invoice_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> BinaryAPIResponse: - """Retrieve a PDF version of a specific invoice by its unique identifier. - - This - endpoint generates a professionally formatted invoice document suitable for - sharing with customers, accounting teams, or for record-keeping purposes. - - ### Use this endpoint to: - - - Provide customers with downloadable or emailable copies of their invoices - - Support accounting and finance teams with official billing documents - - Maintain accurate records of billing transactions for audits and compliance - - ### Key response details: - - - The response is a binary PDF file representing the full invoice - - The PDF includes all standard invoice information such as line items, totals, - billing period, and customer details - - The document is formatted for clarity and professionalism, suitable for - official use - - ### Usage guidelines: - - - Ensure the `invoice_id` corresponds to an existing invoice for the specified - `customer_id` - - The PDF is generated on-demand; frequent requests for the same invoice may - impact performance - - Use appropriate headers to handle the binary response in your application - (e.g., setting `Content-Type: application/pdf`) - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - if not invoice_id: - raise ValueError(f"Expected a non-empty value for `invoice_id` but received {invoice_id!r}") - extra_headers = {"Accept": "application/pdf", **(extra_headers or {})} - return self._get( - f"/v1/customers/{customer_id}/invoices/{invoice_id}/pdf", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=BinaryAPIResponse, - ) - - -class AsyncInvoicesResource(AsyncAPIResource): - """ - [Invoices](https://docs.metronome.com/invoicing/) reflect how much a customer spent during a period, which is the basis for billing. Metronome automatically generates invoices based upon your pricing, packaging, and usage events. Use these endpoints to retrieve invoices. - """ - - @cached_property - def with_raw_response(self) -> AsyncInvoicesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncInvoicesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncInvoicesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncInvoicesResourceWithStreamingResponse(self) - - async def retrieve( - self, - *, - customer_id: str, - invoice_id: str, - skip_zero_qty_line_items: bool | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> InvoiceRetrieveResponse: - """ - Retrieve detailed information for a specific invoice by its unique identifier. - This endpoint returns comprehensive invoice data including line items, applied - credits, totals, and billing period details for both finalized and draft - invoices. - - ### Use this endpoint to: - - - Display historical invoice details in customer-facing dashboards or billing - portals. - - Retrieve current month draft invoices to show customers their month-to-date - spend. - - Access finalized invoices for historical billing records and payment - reconciliation. - - Validate customer pricing and credit applications for customer support - queries. - - ### Key response fields: - - Invoice status (DRAFT, FINALIZED, VOID) Billing period start and end dates Total - amount and amount due after credits Detailed line items broken down by: - - - Customer and contract information - - Invoice line item type - - Product/service name and ID - - Quantity consumed - - Unit and total price - - Time period for usage-based charges - - Applied credits or prepaid commitments - - ### Usage guidelines: - - - Draft invoices update in real-time as usage is reported and may change before - finalization - - The response includes both usage-based line items (e.g., API calls, data - processed) and scheduled charges (e.g., monthly subscriptions, commitment - fees) - - Credit and commitment applications are shown as separate line items with - negative amounts - - For voided invoices, the response will indicate VOID status but retain all - original line item details - - Args: - skip_zero_qty_line_items: If set, all zero quantity line items will be filtered out of the response - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - if not invoice_id: - raise ValueError(f"Expected a non-empty value for `invoice_id` but received {invoice_id!r}") - return await self._get( - f"/v1/customers/{customer_id}/invoices/{invoice_id}", - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=await async_maybe_transform( - {"skip_zero_qty_line_items": skip_zero_qty_line_items}, - invoice_retrieve_params.InvoiceRetrieveParams, - ), - ), - cast_to=InvoiceRetrieveResponse, - ) - - def list( - self, - *, - customer_id: str, - credit_type_id: str | Omit = omit, - ending_before: Union[str, datetime] | Omit = omit, - limit: int | Omit = omit, - next_page: str | Omit = omit, - skip_zero_qty_line_items: bool | Omit = omit, - sort: Literal["date_asc", "date_desc"] | Omit = omit, - starting_on: Union[str, datetime] | Omit = omit, - status: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[Invoice, AsyncCursorPage[Invoice]]: - """ - Retrieves a paginated list of invoices for a specific customer, with flexible - filtering options to narrow results by status, date range, credit type, and - more. This endpoint provides a comprehensive view of a customer's billing - history and current charges, supporting both real-time billing dashboards and - historical reporting needs. - - ### Use this endpoint to: - - - Display historical invoice details in customer-facing dashboards or billing - portals. - - Retrieve current month draft invoices to show customers their month-to-date - spend. - - Access finalized invoices for historical billing records and payment - reconciliation. - - Validate customer pricing and credit applications for customer support - queries. - - Generate financial reports by filtering invoices within specific date ranges - - ### Key response fields: - - Array of invoice objects containing: - - - Invoice ID and status (DRAFT, FINALIZED, VOID) - - Invoice type (USAGE, SCHEDULED) - - Billing period start and end dates - - Issue date and due date - - Total amount, subtotal, and amount due - - Applied credits summary - - Contract ID reference - - External billing provider status (if integrated with Stripe, etc.) - - Pagination metadata `next_page` cursor - - ### Usage guidelines: - - - The endpoint returns invoice summaries; use the Get Invoice endpoint for - detailed line items - - Draft invoices are continuously updated as new usage is reported and will show - real-time spend - - Results are ordered by creation date descending by default (newest first) - - When filtering by date range, the filter applies to the billing period, not - the issue date - - For customers with many invoices, implement pagination to ensure all results - are retrieved External billing provider statuses (like Stripe payment status) - are included when applicable - - Voided invoices are included in results by default unless filtered out by - status - - Args: - credit_type_id: Only return invoices for the specified credit type - - ending_before: RFC 3339 timestamp (exclusive). Invoices will only be returned for billing - periods that end before this time. - - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - skip_zero_qty_line_items: If set, all zero quantity line items will be filtered out of the response - - sort: Invoice sort order by issued_at, e.g. date_asc or date_desc. Defaults to - date_asc. - - starting_on: RFC 3339 timestamp (inclusive). Invoices will only be returned for billing - periods that start at or after this time. - - status: Invoice status, e.g. DRAFT, FINALIZED, or VOID - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - return self._get_api_list( - f"/v1/customers/{customer_id}/invoices", - page=AsyncCursorPage[Invoice], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "credit_type_id": credit_type_id, - "ending_before": ending_before, - "limit": limit, - "next_page": next_page, - "skip_zero_qty_line_items": skip_zero_qty_line_items, - "sort": sort, - "starting_on": starting_on, - "status": status, - }, - invoice_list_params.InvoiceListParams, - ), - ), - model=Invoice, - ) - - async def add_charge( - self, - *, - customer_id: str, - charge_id: str, - customer_plan_id: str, - description: str, - invoice_start_timestamp: Union[str, datetime], - price: float, - quantity: float, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> InvoiceAddChargeResponse: - """Add a one time charge to the specified invoice. - - This is a Plans (deprecated) - endpoint. New clients should implement using Contracts. - - Args: - charge_id: The Metronome ID of the charge to add to the invoice. Note that the charge must - be on a product that is not on the current plan, and the product must have only - fixed charges. - - customer_plan_id: The Metronome ID of the customer plan to add the charge to. - - invoice_start_timestamp: The start_timestamp of the invoice to add the charge to. - - price: The price of the charge. This price will match the currency on the invoice, e.g. - USD cents. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - return await self._post( - f"/v1/customers/{customer_id}/addCharge", - body=await async_maybe_transform( - { - "charge_id": charge_id, - "customer_plan_id": customer_plan_id, - "description": description, - "invoice_start_timestamp": invoice_start_timestamp, - "price": price, - "quantity": quantity, - }, - invoice_add_charge_params.InvoiceAddChargeParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=InvoiceAddChargeResponse, - ) - - def list_breakdowns( - self, - *, - customer_id: str, - ending_before: Union[str, datetime], - starting_on: Union[str, datetime], - credit_type_id: str | Omit = omit, - limit: int | Omit = omit, - next_page: str | Omit = omit, - skip_zero_qty_line_items: bool | Omit = omit, - sort: Literal["date_asc", "date_desc"] | Omit = omit, - status: str | Omit = omit, - window_size: Literal["HOUR", "DAY"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[InvoiceListBreakdownsResponse, AsyncCursorPage[InvoiceListBreakdownsResponse]]: - """ - Retrieve granular time-series breakdowns of invoice data at hourly or daily - intervals. This endpoint transforms standard invoices into detailed timelines, - enabling you to track usage patterns, identify consumption spikes, and provide - customers with transparency into their billing details throughout the billing - period. - - ### Use this endpoint to: - - - Build usage analytics dashboards showing daily or hourly consumption trends - - Identify peak usage periods for capacity planning and cost optimization - - Generate detailed billing reports for finance teams and customer success - - Troubleshoot billing disputes by examining usage patterns at specific times - - Power real-time cost monitoring and alerting systems - - ### Key response fields: - - An array of BreakdownInvoice objects, each containing: - - - All standard invoice fields (ID, customer, commit, line items, totals, status) - - Line items with quantities and costs for that specific period - - `breakdown_start_timestamp`: Start of the specific time window - - `breakdown_end_timestamp`: End of the specific time window - - `next_page`: Pagination cursor for large result sets - - ### Usage guidelines: - - - Time granularity: Set `window_size` to hour or day based on your analysis - needs - - Response limits: Daily breakdowns return up to 35 days; hourly breakdowns - return up to 24 hours per request - - Date filtering: Use `starting_on` and `ending_before` to focus on specific - periods - - Performance: For large date ranges, use pagination to retrieve all data - efficiently - - Backdated usage: If usage events arrive after invoice finalization, breakdowns - will reflect the updated usage - - Zero quantity filtering: Use `skip_zero_qty_line_items=true` to exclude - periods with no usage - - Args: - ending_before: RFC 3339 timestamp. Breakdowns will only be returned for time windows that end - on or before this time. - - starting_on: RFC 3339 timestamp. Breakdowns will only be returned for time windows that start - on or after this time. - - credit_type_id: Only return invoices for the specified credit type - - limit: Max number of results that should be returned. For daily breakdowns, the - response can return up to 35 days worth of breakdowns. For hourly breakdowns, - the response can return up to 24 hours. If there are more results, a cursor to - the next page is returned. - - next_page: Cursor that indicates where the next page of results should start. - - skip_zero_qty_line_items: If set, all zero quantity line items will be filtered out of the response - - sort: Invoice sort order by issued_at, e.g. date_asc or date_desc. Defaults to - date_asc. - - status: Invoice status, e.g. DRAFT or FINALIZED - - window_size: The granularity of the breakdowns to return. Defaults to day. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - return self._get_api_list( - f"/v1/customers/{customer_id}/invoices/breakdowns", - page=AsyncCursorPage[InvoiceListBreakdownsResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "ending_before": ending_before, - "starting_on": starting_on, - "credit_type_id": credit_type_id, - "limit": limit, - "next_page": next_page, - "skip_zero_qty_line_items": skip_zero_qty_line_items, - "sort": sort, - "status": status, - "window_size": window_size, - }, - invoice_list_breakdowns_params.InvoiceListBreakdownsParams, - ), - ), - model=InvoiceListBreakdownsResponse, - ) - - async def retrieve_pdf( - self, - *, - customer_id: str, - invoice_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncBinaryAPIResponse: - """Retrieve a PDF version of a specific invoice by its unique identifier. - - This - endpoint generates a professionally formatted invoice document suitable for - sharing with customers, accounting teams, or for record-keeping purposes. - - ### Use this endpoint to: - - - Provide customers with downloadable or emailable copies of their invoices - - Support accounting and finance teams with official billing documents - - Maintain accurate records of billing transactions for audits and compliance - - ### Key response details: - - - The response is a binary PDF file representing the full invoice - - The PDF includes all standard invoice information such as line items, totals, - billing period, and customer details - - The document is formatted for clarity and professionalism, suitable for - official use - - ### Usage guidelines: - - - Ensure the `invoice_id` corresponds to an existing invoice for the specified - `customer_id` - - The PDF is generated on-demand; frequent requests for the same invoice may - impact performance - - Use appropriate headers to handle the binary response in your application - (e.g., setting `Content-Type: application/pdf`) - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - if not invoice_id: - raise ValueError(f"Expected a non-empty value for `invoice_id` but received {invoice_id!r}") - extra_headers = {"Accept": "application/pdf", **(extra_headers or {})} - return await self._get( - f"/v1/customers/{customer_id}/invoices/{invoice_id}/pdf", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=AsyncBinaryAPIResponse, - ) - - -class InvoicesResourceWithRawResponse: - def __init__(self, invoices: InvoicesResource) -> None: - self._invoices = invoices - - self.retrieve = to_raw_response_wrapper( - invoices.retrieve, - ) - self.list = to_raw_response_wrapper( - invoices.list, - ) - self.add_charge = to_raw_response_wrapper( - invoices.add_charge, - ) - self.list_breakdowns = to_raw_response_wrapper( - invoices.list_breakdowns, - ) - self.retrieve_pdf = to_custom_raw_response_wrapper( - invoices.retrieve_pdf, - BinaryAPIResponse, - ) - - -class AsyncInvoicesResourceWithRawResponse: - def __init__(self, invoices: AsyncInvoicesResource) -> None: - self._invoices = invoices - - self.retrieve = async_to_raw_response_wrapper( - invoices.retrieve, - ) - self.list = async_to_raw_response_wrapper( - invoices.list, - ) - self.add_charge = async_to_raw_response_wrapper( - invoices.add_charge, - ) - self.list_breakdowns = async_to_raw_response_wrapper( - invoices.list_breakdowns, - ) - self.retrieve_pdf = async_to_custom_raw_response_wrapper( - invoices.retrieve_pdf, - AsyncBinaryAPIResponse, - ) - - -class InvoicesResourceWithStreamingResponse: - def __init__(self, invoices: InvoicesResource) -> None: - self._invoices = invoices - - self.retrieve = to_streamed_response_wrapper( - invoices.retrieve, - ) - self.list = to_streamed_response_wrapper( - invoices.list, - ) - self.add_charge = to_streamed_response_wrapper( - invoices.add_charge, - ) - self.list_breakdowns = to_streamed_response_wrapper( - invoices.list_breakdowns, - ) - self.retrieve_pdf = to_custom_streamed_response_wrapper( - invoices.retrieve_pdf, - StreamedBinaryAPIResponse, - ) - - -class AsyncInvoicesResourceWithStreamingResponse: - def __init__(self, invoices: AsyncInvoicesResource) -> None: - self._invoices = invoices - - self.retrieve = async_to_streamed_response_wrapper( - invoices.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - invoices.list, - ) - self.add_charge = async_to_streamed_response_wrapper( - invoices.add_charge, - ) - self.list_breakdowns = async_to_streamed_response_wrapper( - invoices.list_breakdowns, - ) - self.retrieve_pdf = async_to_custom_streamed_response_wrapper( - invoices.retrieve_pdf, - AsyncStreamedBinaryAPIResponse, - ) diff --git a/src/metronome/resources/v1/customers/named_schedules.py b/src/metronome/resources/v1/customers/named_schedules.py deleted file mode 100644 index 4203ec66d..000000000 --- a/src/metronome/resources/v1/customers/named_schedules.py +++ /dev/null @@ -1,334 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime - -import httpx - -from ...._types import Body, Omit, Query, Headers, NoneType, NotGiven, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ...._base_client import make_request_options -from ....types.v1.customers import named_schedule_update_params, named_schedule_retrieve_params -from ....types.v1.customers.named_schedule_retrieve_response import NamedScheduleRetrieveResponse - -__all__ = ["NamedSchedulesResource", "AsyncNamedSchedulesResource"] - - -class NamedSchedulesResource(SyncAPIResource): - """Named schedules are used for storing custom data that can change over time. - - Named schedules are often used in custom pricing logic. - """ - - @cached_property - def with_raw_response(self) -> NamedSchedulesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return NamedSchedulesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> NamedSchedulesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return NamedSchedulesResourceWithStreamingResponse(self) - - def retrieve( - self, - *, - customer_id: str, - schedule_name: str, - covering_date: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> NamedScheduleRetrieveResponse: - """Get a named schedule for the given customer. - - This endpoint's availability is - dependent on your client's configuration. - - Args: - customer_id: ID of the customer whose named schedule is to be retrieved - - schedule_name: The identifier for the schedule to be retrieved - - covering_date: If provided, at most one schedule segment will be returned (the one that covers - this date). If not provided, all segments will be returned. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/customers/getNamedSchedule", - body=maybe_transform( - { - "customer_id": customer_id, - "schedule_name": schedule_name, - "covering_date": covering_date, - }, - named_schedule_retrieve_params.NamedScheduleRetrieveParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NamedScheduleRetrieveResponse, - ) - - def update( - self, - *, - customer_id: str, - schedule_name: str, - starting_at: Union[str, datetime], - value: object, - ending_before: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """Update a named schedule for the given customer. - - This endpoint's availability is - dependent on your client's configuration. - - Args: - customer_id: ID of the customer whose named schedule is to be updated - - schedule_name: The identifier for the schedule to be updated - - value: The value to set for the named schedule. The structure of this object is - specific to the named schedule. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._post( - "/v1/customers/updateNamedSchedule", - body=maybe_transform( - { - "customer_id": customer_id, - "schedule_name": schedule_name, - "starting_at": starting_at, - "value": value, - "ending_before": ending_before, - }, - named_schedule_update_params.NamedScheduleUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class AsyncNamedSchedulesResource(AsyncAPIResource): - """Named schedules are used for storing custom data that can change over time. - - Named schedules are often used in custom pricing logic. - """ - - @cached_property - def with_raw_response(self) -> AsyncNamedSchedulesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncNamedSchedulesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncNamedSchedulesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncNamedSchedulesResourceWithStreamingResponse(self) - - async def retrieve( - self, - *, - customer_id: str, - schedule_name: str, - covering_date: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> NamedScheduleRetrieveResponse: - """Get a named schedule for the given customer. - - This endpoint's availability is - dependent on your client's configuration. - - Args: - customer_id: ID of the customer whose named schedule is to be retrieved - - schedule_name: The identifier for the schedule to be retrieved - - covering_date: If provided, at most one schedule segment will be returned (the one that covers - this date). If not provided, all segments will be returned. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/customers/getNamedSchedule", - body=await async_maybe_transform( - { - "customer_id": customer_id, - "schedule_name": schedule_name, - "covering_date": covering_date, - }, - named_schedule_retrieve_params.NamedScheduleRetrieveParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NamedScheduleRetrieveResponse, - ) - - async def update( - self, - *, - customer_id: str, - schedule_name: str, - starting_at: Union[str, datetime], - value: object, - ending_before: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """Update a named schedule for the given customer. - - This endpoint's availability is - dependent on your client's configuration. - - Args: - customer_id: ID of the customer whose named schedule is to be updated - - schedule_name: The identifier for the schedule to be updated - - value: The value to set for the named schedule. The structure of this object is - specific to the named schedule. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._post( - "/v1/customers/updateNamedSchedule", - body=await async_maybe_transform( - { - "customer_id": customer_id, - "schedule_name": schedule_name, - "starting_at": starting_at, - "value": value, - "ending_before": ending_before, - }, - named_schedule_update_params.NamedScheduleUpdateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - -class NamedSchedulesResourceWithRawResponse: - def __init__(self, named_schedules: NamedSchedulesResource) -> None: - self._named_schedules = named_schedules - - self.retrieve = to_raw_response_wrapper( - named_schedules.retrieve, - ) - self.update = to_raw_response_wrapper( - named_schedules.update, - ) - - -class AsyncNamedSchedulesResourceWithRawResponse: - def __init__(self, named_schedules: AsyncNamedSchedulesResource) -> None: - self._named_schedules = named_schedules - - self.retrieve = async_to_raw_response_wrapper( - named_schedules.retrieve, - ) - self.update = async_to_raw_response_wrapper( - named_schedules.update, - ) - - -class NamedSchedulesResourceWithStreamingResponse: - def __init__(self, named_schedules: NamedSchedulesResource) -> None: - self._named_schedules = named_schedules - - self.retrieve = to_streamed_response_wrapper( - named_schedules.retrieve, - ) - self.update = to_streamed_response_wrapper( - named_schedules.update, - ) - - -class AsyncNamedSchedulesResourceWithStreamingResponse: - def __init__(self, named_schedules: AsyncNamedSchedulesResource) -> None: - self._named_schedules = named_schedules - - self.retrieve = async_to_streamed_response_wrapper( - named_schedules.retrieve, - ) - self.update = async_to_streamed_response_wrapper( - named_schedules.update, - ) diff --git a/src/metronome/resources/v1/customers/plans.py b/src/metronome/resources/v1/customers/plans.py deleted file mode 100644 index 4475a21e1..000000000 --- a/src/metronome/resources/v1/customers/plans.py +++ /dev/null @@ -1,645 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from datetime import datetime - -import httpx - -from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ....pagination import SyncCursorPage, AsyncCursorPage -from ...._base_client import AsyncPaginator, make_request_options -from ....types.v1.customers import ( - plan_add_params, - plan_end_params, - plan_list_params, - plan_list_price_adjustments_params, -) -from ....types.v1.customers.plan_add_response import PlanAddResponse -from ....types.v1.customers.plan_end_response import PlanEndResponse -from ....types.v1.customers.plan_list_response import PlanListResponse -from ....types.v1.customers.plan_list_price_adjustments_response import PlanListPriceAdjustmentsResponse - -__all__ = ["PlansResource", "AsyncPlansResource"] - - -class PlansResource(SyncAPIResource): - """ - [Plans](https://docs.metronome.com/pricing-and-packaging/create-plans/) determine the base pricing for a customer. Use these endpoints to add a plan to a customer, end a customer plan, retrieve plans, and retrieve plan details. Create plans in the [Metronome app](https://app.metronome.com/plans). - """ - - @cached_property - def with_raw_response(self) -> PlansResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return PlansResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> PlansResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return PlansResourceWithStreamingResponse(self) - - def list( - self, - *, - customer_id: str, - limit: int | Omit = omit, - next_page: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[PlanListResponse]: - """List the given customer's plans in reverse-chronological order. - - This is a Plans - (deprecated) endpoint. New clients should implement using Contracts. - - Args: - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - return self._get_api_list( - f"/v1/customers/{customer_id}/plans", - page=SyncCursorPage[PlanListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - plan_list_params.PlanListParams, - ), - ), - model=PlanListResponse, - ) - - def add( - self, - *, - customer_id: str, - plan_id: str, - starting_on: Union[str, datetime], - ending_before: Union[str, datetime] | Omit = omit, - net_payment_terms_days: float | Omit = omit, - overage_rate_adjustments: Iterable[plan_add_params.OverageRateAdjustment] | Omit = omit, - price_adjustments: Iterable[plan_add_params.PriceAdjustment] | Omit = omit, - trial_spec: plan_add_params.TrialSpec | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> PlanAddResponse: - """Associate an existing customer with a plan for a specified date range. - - See the - [price adjustments documentation](https://plans-docs.metronome.com/pricing/managing-plans/#price-adjustments) - for details on the price adjustments. This is a Plans (deprecated) endpoint. New - clients should implement using Contracts. - - Args: - starting_on: RFC 3339 timestamp for when the plan becomes active for this customer. Must be - at 0:00 UTC (midnight). - - ending_before: RFC 3339 timestamp for when the plan ends (exclusive) for this customer. Must be - at 0:00 UTC (midnight). - - net_payment_terms_days: Number of days after issuance of invoice after which the invoice is due (e.g. - Net 30). - - overage_rate_adjustments: An optional list of overage rates that override the rates of the original plan - configuration. These new rates will apply to all pricing ramps. - - price_adjustments: A list of price adjustments can be applied on top of the pricing in the plans. - See the - [price adjustments documentation](https://plans-docs.metronome.com/pricing/managing-plans/#price-adjustments) - for details. - - trial_spec: A custom trial can be set for the customer's plan. See the - [trial configuration documentation](https://docs.metronome.com/provisioning/configure-trials/) - for details. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - return self._post( - f"/v1/customers/{customer_id}/plans/add", - body=maybe_transform( - { - "plan_id": plan_id, - "starting_on": starting_on, - "ending_before": ending_before, - "net_payment_terms_days": net_payment_terms_days, - "overage_rate_adjustments": overage_rate_adjustments, - "price_adjustments": price_adjustments, - "trial_spec": trial_spec, - }, - plan_add_params.PlanAddParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=PlanAddResponse, - ) - - def end( - self, - *, - customer_id: str, - customer_plan_id: str, - ending_before: Union[str, datetime] | Omit = omit, - void_invoices: bool | Omit = omit, - void_stripe_invoices: bool | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> PlanEndResponse: - """Change the end date of a customer's plan. - - This is a Plans (deprecated) endpoint. - New clients should implement using Contracts. - - Args: - ending_before: RFC 3339 timestamp for when the plan ends (exclusive) for this customer. Must be - at 0:00 UTC (midnight). If not provided, the plan end date will be cleared. - - void_invoices: If true, plan end date can be before the last finalized invoice date. Any - invoices generated after the plan end date will be voided. - - void_stripe_invoices: Only applicable when void_invoices is set to true. If true, for every invoice - that is voided we will also attempt to void/delete the stripe invoice (if any). - Stripe invoices will be voided if finalized or deleted if still in draft state. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - if not customer_plan_id: - raise ValueError(f"Expected a non-empty value for `customer_plan_id` but received {customer_plan_id!r}") - return self._post( - f"/v1/customers/{customer_id}/plans/{customer_plan_id}/end", - body=maybe_transform( - { - "ending_before": ending_before, - "void_invoices": void_invoices, - "void_stripe_invoices": void_stripe_invoices, - }, - plan_end_params.PlanEndParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=PlanEndResponse, - ) - - def list_price_adjustments( - self, - *, - customer_id: str, - customer_plan_id: str, - limit: int | Omit = omit, - next_page: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[PlanListPriceAdjustmentsResponse]: - """Lists a customer plans adjustments. - - See the - [price adjustments documentation](https://plans-docs.metronome.com/pricing/managing-plans/#price-adjustments) - for details. This is a Plans (deprecated) endpoint. New clients should implement - using Contracts. - - Args: - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - if not customer_plan_id: - raise ValueError(f"Expected a non-empty value for `customer_plan_id` but received {customer_plan_id!r}") - return self._get_api_list( - f"/v1/customers/{customer_id}/plans/{customer_plan_id}/priceAdjustments", - page=SyncCursorPage[PlanListPriceAdjustmentsResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - plan_list_price_adjustments_params.PlanListPriceAdjustmentsParams, - ), - ), - model=PlanListPriceAdjustmentsResponse, - ) - - -class AsyncPlansResource(AsyncAPIResource): - """ - [Plans](https://docs.metronome.com/pricing-and-packaging/create-plans/) determine the base pricing for a customer. Use these endpoints to add a plan to a customer, end a customer plan, retrieve plans, and retrieve plan details. Create plans in the [Metronome app](https://app.metronome.com/plans). - """ - - @cached_property - def with_raw_response(self) -> AsyncPlansResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncPlansResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncPlansResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncPlansResourceWithStreamingResponse(self) - - def list( - self, - *, - customer_id: str, - limit: int | Omit = omit, - next_page: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[PlanListResponse, AsyncCursorPage[PlanListResponse]]: - """List the given customer's plans in reverse-chronological order. - - This is a Plans - (deprecated) endpoint. New clients should implement using Contracts. - - Args: - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - return self._get_api_list( - f"/v1/customers/{customer_id}/plans", - page=AsyncCursorPage[PlanListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - plan_list_params.PlanListParams, - ), - ), - model=PlanListResponse, - ) - - async def add( - self, - *, - customer_id: str, - plan_id: str, - starting_on: Union[str, datetime], - ending_before: Union[str, datetime] | Omit = omit, - net_payment_terms_days: float | Omit = omit, - overage_rate_adjustments: Iterable[plan_add_params.OverageRateAdjustment] | Omit = omit, - price_adjustments: Iterable[plan_add_params.PriceAdjustment] | Omit = omit, - trial_spec: plan_add_params.TrialSpec | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> PlanAddResponse: - """Associate an existing customer with a plan for a specified date range. - - See the - [price adjustments documentation](https://plans-docs.metronome.com/pricing/managing-plans/#price-adjustments) - for details on the price adjustments. This is a Plans (deprecated) endpoint. New - clients should implement using Contracts. - - Args: - starting_on: RFC 3339 timestamp for when the plan becomes active for this customer. Must be - at 0:00 UTC (midnight). - - ending_before: RFC 3339 timestamp for when the plan ends (exclusive) for this customer. Must be - at 0:00 UTC (midnight). - - net_payment_terms_days: Number of days after issuance of invoice after which the invoice is due (e.g. - Net 30). - - overage_rate_adjustments: An optional list of overage rates that override the rates of the original plan - configuration. These new rates will apply to all pricing ramps. - - price_adjustments: A list of price adjustments can be applied on top of the pricing in the plans. - See the - [price adjustments documentation](https://plans-docs.metronome.com/pricing/managing-plans/#price-adjustments) - for details. - - trial_spec: A custom trial can be set for the customer's plan. See the - [trial configuration documentation](https://docs.metronome.com/provisioning/configure-trials/) - for details. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - return await self._post( - f"/v1/customers/{customer_id}/plans/add", - body=await async_maybe_transform( - { - "plan_id": plan_id, - "starting_on": starting_on, - "ending_before": ending_before, - "net_payment_terms_days": net_payment_terms_days, - "overage_rate_adjustments": overage_rate_adjustments, - "price_adjustments": price_adjustments, - "trial_spec": trial_spec, - }, - plan_add_params.PlanAddParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=PlanAddResponse, - ) - - async def end( - self, - *, - customer_id: str, - customer_plan_id: str, - ending_before: Union[str, datetime] | Omit = omit, - void_invoices: bool | Omit = omit, - void_stripe_invoices: bool | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> PlanEndResponse: - """Change the end date of a customer's plan. - - This is a Plans (deprecated) endpoint. - New clients should implement using Contracts. - - Args: - ending_before: RFC 3339 timestamp for when the plan ends (exclusive) for this customer. Must be - at 0:00 UTC (midnight). If not provided, the plan end date will be cleared. - - void_invoices: If true, plan end date can be before the last finalized invoice date. Any - invoices generated after the plan end date will be voided. - - void_stripe_invoices: Only applicable when void_invoices is set to true. If true, for every invoice - that is voided we will also attempt to void/delete the stripe invoice (if any). - Stripe invoices will be voided if finalized or deleted if still in draft state. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - if not customer_plan_id: - raise ValueError(f"Expected a non-empty value for `customer_plan_id` but received {customer_plan_id!r}") - return await self._post( - f"/v1/customers/{customer_id}/plans/{customer_plan_id}/end", - body=await async_maybe_transform( - { - "ending_before": ending_before, - "void_invoices": void_invoices, - "void_stripe_invoices": void_stripe_invoices, - }, - plan_end_params.PlanEndParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=PlanEndResponse, - ) - - def list_price_adjustments( - self, - *, - customer_id: str, - customer_plan_id: str, - limit: int | Omit = omit, - next_page: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[PlanListPriceAdjustmentsResponse, AsyncCursorPage[PlanListPriceAdjustmentsResponse]]: - """Lists a customer plans adjustments. - - See the - [price adjustments documentation](https://plans-docs.metronome.com/pricing/managing-plans/#price-adjustments) - for details. This is a Plans (deprecated) endpoint. New clients should implement - using Contracts. - - Args: - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not customer_id: - raise ValueError(f"Expected a non-empty value for `customer_id` but received {customer_id!r}") - if not customer_plan_id: - raise ValueError(f"Expected a non-empty value for `customer_plan_id` but received {customer_plan_id!r}") - return self._get_api_list( - f"/v1/customers/{customer_id}/plans/{customer_plan_id}/priceAdjustments", - page=AsyncCursorPage[PlanListPriceAdjustmentsResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - plan_list_price_adjustments_params.PlanListPriceAdjustmentsParams, - ), - ), - model=PlanListPriceAdjustmentsResponse, - ) - - -class PlansResourceWithRawResponse: - def __init__(self, plans: PlansResource) -> None: - self._plans = plans - - self.list = to_raw_response_wrapper( - plans.list, - ) - self.add = to_raw_response_wrapper( - plans.add, - ) - self.end = to_raw_response_wrapper( - plans.end, - ) - self.list_price_adjustments = to_raw_response_wrapper( - plans.list_price_adjustments, - ) - - -class AsyncPlansResourceWithRawResponse: - def __init__(self, plans: AsyncPlansResource) -> None: - self._plans = plans - - self.list = async_to_raw_response_wrapper( - plans.list, - ) - self.add = async_to_raw_response_wrapper( - plans.add, - ) - self.end = async_to_raw_response_wrapper( - plans.end, - ) - self.list_price_adjustments = async_to_raw_response_wrapper( - plans.list_price_adjustments, - ) - - -class PlansResourceWithStreamingResponse: - def __init__(self, plans: PlansResource) -> None: - self._plans = plans - - self.list = to_streamed_response_wrapper( - plans.list, - ) - self.add = to_streamed_response_wrapper( - plans.add, - ) - self.end = to_streamed_response_wrapper( - plans.end, - ) - self.list_price_adjustments = to_streamed_response_wrapper( - plans.list_price_adjustments, - ) - - -class AsyncPlansResourceWithStreamingResponse: - def __init__(self, plans: AsyncPlansResource) -> None: - self._plans = plans - - self.list = async_to_streamed_response_wrapper( - plans.list, - ) - self.add = async_to_streamed_response_wrapper( - plans.add, - ) - self.end = async_to_streamed_response_wrapper( - plans.end, - ) - self.list_price_adjustments = async_to_streamed_response_wrapper( - plans.list_price_adjustments, - ) diff --git a/src/metronome/resources/v1/dashboards.py b/src/metronome/resources/v1/dashboards.py deleted file mode 100644 index ba371e294..000000000 --- a/src/metronome/resources/v1/dashboards.py +++ /dev/null @@ -1,272 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable -from typing_extensions import Literal - -import httpx - -from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ...types.v1 import dashboard_get_embeddable_url_params -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ..._base_client import make_request_options -from ...types.v1.dashboard_get_embeddable_url_response import DashboardGetEmbeddableURLResponse - -__all__ = ["DashboardsResource", "AsyncDashboardsResource"] - - -class DashboardsResource(SyncAPIResource): - """ - [Customers](https://docs.metronome.com/provisioning/create-customers/) in Metronome represent your users for all billing and reporting. Use these endpoints to create, retrieve, update, and archive customers and their billing configuration. - """ - - @cached_property - def with_raw_response(self) -> DashboardsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return DashboardsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> DashboardsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return DashboardsResourceWithStreamingResponse(self) - - def get_embeddable_url( - self, - *, - customer_id: str, - dashboard: Literal["invoices", "usage", "credits", "commits_and_credits"], - bm_group_key_overrides: Iterable[dashboard_get_embeddable_url_params.BmGroupKeyOverride] | Omit = omit, - color_overrides: Iterable[dashboard_get_embeddable_url_params.ColorOverride] | Omit = omit, - dashboard_options: Iterable[dashboard_get_embeddable_url_params.DashboardOption] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> DashboardGetEmbeddableURLResponse: - """ - Generate secure, embeddable dashboard URLs that allow you to seamlessly - integrate Metronome's billing visualizations directly into your application. - This endpoint creates authenticated iframe-ready URLs for customer-specific - dashboards, providing a white-labeled billing experience without building custom - UI. - - ### Use this endpoint to: - - - Embed billing dashboards directly in your customer portal or admin interface - - Provide self-service access to invoices, usage data, and credit balances - - Build white-labeled billing experiences with minimal development effort - - ### Key response fields: - - - A secure, time-limited URL that can be embedded in an iframe - - The URL includes authentication tokens and configuration parameters - - URLs are customer-specific and respect your security settings - - ### Usage guidelines: - - - Dashboard types: Choose from `invoices`, `usage`, or `commits_and_credits` - - Customization options: - - `dashboard_options`: Configure whether you want invoices to show zero usage - line items - - `color_overrides`: Match your brand's color palette - - `bm_group_key_overrides`: Customize how dimensions are displayed (for the - usage embeddable dashboard) - - Iframe implementation: Embed the returned URL directly in an iframe element - - Responsive design: Dashboards automatically adapt to container dimensions - - Args: - dashboard: The type of dashboard to retrieve. - - bm_group_key_overrides: Optional list of billable metric group key overrides - - color_overrides: Optional list of colors to override - - dashboard_options: Optional dashboard specific options - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/dashboards/getEmbeddableUrl", - body=maybe_transform( - { - "customer_id": customer_id, - "dashboard": dashboard, - "bm_group_key_overrides": bm_group_key_overrides, - "color_overrides": color_overrides, - "dashboard_options": dashboard_options, - }, - dashboard_get_embeddable_url_params.DashboardGetEmbeddableURLParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=DashboardGetEmbeddableURLResponse, - ) - - -class AsyncDashboardsResource(AsyncAPIResource): - """ - [Customers](https://docs.metronome.com/provisioning/create-customers/) in Metronome represent your users for all billing and reporting. Use these endpoints to create, retrieve, update, and archive customers and their billing configuration. - """ - - @cached_property - def with_raw_response(self) -> AsyncDashboardsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncDashboardsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncDashboardsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncDashboardsResourceWithStreamingResponse(self) - - async def get_embeddable_url( - self, - *, - customer_id: str, - dashboard: Literal["invoices", "usage", "credits", "commits_and_credits"], - bm_group_key_overrides: Iterable[dashboard_get_embeddable_url_params.BmGroupKeyOverride] | Omit = omit, - color_overrides: Iterable[dashboard_get_embeddable_url_params.ColorOverride] | Omit = omit, - dashboard_options: Iterable[dashboard_get_embeddable_url_params.DashboardOption] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> DashboardGetEmbeddableURLResponse: - """ - Generate secure, embeddable dashboard URLs that allow you to seamlessly - integrate Metronome's billing visualizations directly into your application. - This endpoint creates authenticated iframe-ready URLs for customer-specific - dashboards, providing a white-labeled billing experience without building custom - UI. - - ### Use this endpoint to: - - - Embed billing dashboards directly in your customer portal or admin interface - - Provide self-service access to invoices, usage data, and credit balances - - Build white-labeled billing experiences with minimal development effort - - ### Key response fields: - - - A secure, time-limited URL that can be embedded in an iframe - - The URL includes authentication tokens and configuration parameters - - URLs are customer-specific and respect your security settings - - ### Usage guidelines: - - - Dashboard types: Choose from `invoices`, `usage`, or `commits_and_credits` - - Customization options: - - `dashboard_options`: Configure whether you want invoices to show zero usage - line items - - `color_overrides`: Match your brand's color palette - - `bm_group_key_overrides`: Customize how dimensions are displayed (for the - usage embeddable dashboard) - - Iframe implementation: Embed the returned URL directly in an iframe element - - Responsive design: Dashboards automatically adapt to container dimensions - - Args: - dashboard: The type of dashboard to retrieve. - - bm_group_key_overrides: Optional list of billable metric group key overrides - - color_overrides: Optional list of colors to override - - dashboard_options: Optional dashboard specific options - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/dashboards/getEmbeddableUrl", - body=await async_maybe_transform( - { - "customer_id": customer_id, - "dashboard": dashboard, - "bm_group_key_overrides": bm_group_key_overrides, - "color_overrides": color_overrides, - "dashboard_options": dashboard_options, - }, - dashboard_get_embeddable_url_params.DashboardGetEmbeddableURLParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=DashboardGetEmbeddableURLResponse, - ) - - -class DashboardsResourceWithRawResponse: - def __init__(self, dashboards: DashboardsResource) -> None: - self._dashboards = dashboards - - self.get_embeddable_url = to_raw_response_wrapper( - dashboards.get_embeddable_url, - ) - - -class AsyncDashboardsResourceWithRawResponse: - def __init__(self, dashboards: AsyncDashboardsResource) -> None: - self._dashboards = dashboards - - self.get_embeddable_url = async_to_raw_response_wrapper( - dashboards.get_embeddable_url, - ) - - -class DashboardsResourceWithStreamingResponse: - def __init__(self, dashboards: DashboardsResource) -> None: - self._dashboards = dashboards - - self.get_embeddable_url = to_streamed_response_wrapper( - dashboards.get_embeddable_url, - ) - - -class AsyncDashboardsResourceWithStreamingResponse: - def __init__(self, dashboards: AsyncDashboardsResource) -> None: - self._dashboards = dashboards - - self.get_embeddable_url = async_to_streamed_response_wrapper( - dashboards.get_embeddable_url, - ) diff --git a/src/metronome/resources/v1/invoices.py b/src/metronome/resources/v1/invoices.py deleted file mode 100644 index 0f5cebe28..000000000 --- a/src/metronome/resources/v1/invoices.py +++ /dev/null @@ -1,298 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import httpx - -from ..._types import Body, Query, Headers, NotGiven, not_given -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ...types.v1 import invoice_void_params, invoice_regenerate_params -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ..._base_client import make_request_options -from ...types.v1.invoice_void_response import InvoiceVoidResponse -from ...types.v1.invoice_regenerate_response import InvoiceRegenerateResponse - -__all__ = ["InvoicesResource", "AsyncInvoicesResource"] - - -class InvoicesResource(SyncAPIResource): - """ - [Invoices](https://docs.metronome.com/invoicing/) reflect how much a customer spent during a period, which is the basis for billing. Metronome automatically generates invoices based upon your pricing, packaging, and usage events. Use these endpoints to retrieve invoices. - """ - - @cached_property - def with_raw_response(self) -> InvoicesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return InvoicesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> InvoicesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return InvoicesResourceWithStreamingResponse(self) - - def regenerate( - self, - *, - id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> InvoiceRegenerateResponse: - """ - This endpoint regenerates a voided invoice and recalculates the invoice based on - up-to-date rates, available balances, and other fees regardless of the billing - period. - - ### Use this endpoint to: - - Recalculate an invoice with updated rate terms, available balance, and fees to - correct billing disputes or discrepancies - - ### Key response fields: - - The regenerated invoice id, which is distinct from the previously voided - invoice. - - ### Usage guidelines: - - If an invoice is attached to a contract with a billing provider on it, the - regenerated invoice will be distributed based on the configuration. - - Args: - id: The invoice id to regenerate - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/invoices/regenerate", - body=maybe_transform({"id": id}, invoice_regenerate_params.InvoiceRegenerateParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=InvoiceRegenerateResponse, - ) - - def void( - self, - *, - id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> InvoiceVoidResponse: - """ - Permanently cancels an invoice by setting its status to voided, preventing - collection and removing it from customer billing. Use this to correct billing - errors, cancel incorrect charges, or handle disputed invoices that should not be - collected. Returns the voided invoice ID with the status change applied - immediately to stop any payment processing. - - Args: - id: The invoice id to void - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/invoices/void", - body=maybe_transform({"id": id}, invoice_void_params.InvoiceVoidParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=InvoiceVoidResponse, - ) - - -class AsyncInvoicesResource(AsyncAPIResource): - """ - [Invoices](https://docs.metronome.com/invoicing/) reflect how much a customer spent during a period, which is the basis for billing. Metronome automatically generates invoices based upon your pricing, packaging, and usage events. Use these endpoints to retrieve invoices. - """ - - @cached_property - def with_raw_response(self) -> AsyncInvoicesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncInvoicesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncInvoicesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncInvoicesResourceWithStreamingResponse(self) - - async def regenerate( - self, - *, - id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> InvoiceRegenerateResponse: - """ - This endpoint regenerates a voided invoice and recalculates the invoice based on - up-to-date rates, available balances, and other fees regardless of the billing - period. - - ### Use this endpoint to: - - Recalculate an invoice with updated rate terms, available balance, and fees to - correct billing disputes or discrepancies - - ### Key response fields: - - The regenerated invoice id, which is distinct from the previously voided - invoice. - - ### Usage guidelines: - - If an invoice is attached to a contract with a billing provider on it, the - regenerated invoice will be distributed based on the configuration. - - Args: - id: The invoice id to regenerate - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/invoices/regenerate", - body=await async_maybe_transform({"id": id}, invoice_regenerate_params.InvoiceRegenerateParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=InvoiceRegenerateResponse, - ) - - async def void( - self, - *, - id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> InvoiceVoidResponse: - """ - Permanently cancels an invoice by setting its status to voided, preventing - collection and removing it from customer billing. Use this to correct billing - errors, cancel incorrect charges, or handle disputed invoices that should not be - collected. Returns the voided invoice ID with the status change applied - immediately to stop any payment processing. - - Args: - id: The invoice id to void - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/invoices/void", - body=await async_maybe_transform({"id": id}, invoice_void_params.InvoiceVoidParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=InvoiceVoidResponse, - ) - - -class InvoicesResourceWithRawResponse: - def __init__(self, invoices: InvoicesResource) -> None: - self._invoices = invoices - - self.regenerate = to_raw_response_wrapper( - invoices.regenerate, - ) - self.void = to_raw_response_wrapper( - invoices.void, - ) - - -class AsyncInvoicesResourceWithRawResponse: - def __init__(self, invoices: AsyncInvoicesResource) -> None: - self._invoices = invoices - - self.regenerate = async_to_raw_response_wrapper( - invoices.regenerate, - ) - self.void = async_to_raw_response_wrapper( - invoices.void, - ) - - -class InvoicesResourceWithStreamingResponse: - def __init__(self, invoices: InvoicesResource) -> None: - self._invoices = invoices - - self.regenerate = to_streamed_response_wrapper( - invoices.regenerate, - ) - self.void = to_streamed_response_wrapper( - invoices.void, - ) - - -class AsyncInvoicesResourceWithStreamingResponse: - def __init__(self, invoices: AsyncInvoicesResource) -> None: - self._invoices = invoices - - self.regenerate = async_to_streamed_response_wrapper( - invoices.regenerate, - ) - self.void = async_to_streamed_response_wrapper( - invoices.void, - ) diff --git a/src/metronome/resources/v1/packages.py b/src/metronome/resources/v1/packages.py deleted file mode 100644 index 2357e46b0..000000000 --- a/src/metronome/resources/v1/packages.py +++ /dev/null @@ -1,892 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from datetime import datetime -from typing_extensions import Literal - -import httpx - -from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ...types.v1 import ( - package_list_params, - package_create_params, - package_archive_params, - package_retrieve_params, - package_list_contracts_on_package_params, -) -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ...pagination import SyncCursorPage, AsyncCursorPage -from ..._base_client import AsyncPaginator, make_request_options -from ...types.v1.package_list_response import PackageListResponse -from ...types.v1.package_create_response import PackageCreateResponse -from ...types.v1.package_archive_response import PackageArchiveResponse -from ...types.v1.package_retrieve_response import PackageRetrieveResponse -from ...types.shared_params.spend_threshold_configuration import SpendThresholdConfiguration -from ...types.v1.package_list_contracts_on_package_response import PackageListContractsOnPackageResponse -from ...types.shared_params.prepaid_balance_threshold_configuration import PrepaidBalanceThresholdConfiguration - -__all__ = ["PackagesResource", "AsyncPackagesResource"] - - -class PackagesResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> PackagesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return PackagesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> PackagesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return PackagesResourceWithStreamingResponse(self) - - def create( - self, - *, - name: str, - aliases: Iterable[package_create_params.Alias] | Omit = omit, - billing_anchor_date: Literal["contract_start_date", "first_billing_period"] | Omit = omit, - billing_provider: Literal["aws_marketplace", "azure_marketplace", "gcp_marketplace", "stripe", "netsuite"] - | Omit = omit, - commits: Iterable[package_create_params.Commit] | Omit = omit, - contract_name: str | Omit = omit, - credits: Iterable[package_create_params.Credit] | Omit = omit, - delivery_method: Literal["direct_to_billing_provider", "aws_sqs", "tackle", "aws_sns"] | Omit = omit, - duration: package_create_params.Duration | Omit = omit, - multiplier_override_prioritization: Literal["LOWEST_MULTIPLIER", "EXPLICIT"] | Omit = omit, - net_payment_terms_days: float | Omit = omit, - overrides: Iterable[package_create_params.Override] | Omit = omit, - prepaid_balance_threshold_configuration: PrepaidBalanceThresholdConfiguration | Omit = omit, - rate_card_alias: str | Omit = omit, - rate_card_id: str | Omit = omit, - recurring_commits: Iterable[package_create_params.RecurringCommit] | Omit = omit, - recurring_credits: Iterable[package_create_params.RecurringCredit] | Omit = omit, - scheduled_charges: Iterable[package_create_params.ScheduledCharge] | Omit = omit, - scheduled_charges_on_usage_invoices: Literal["ALL"] | Omit = omit, - spend_threshold_configuration: SpendThresholdConfiguration | Omit = omit, - subscriptions: Iterable[package_create_params.Subscription] | Omit = omit, - uniqueness_key: str | Omit = omit, - usage_statement_schedule: package_create_params.UsageStatementSchedule | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> PackageCreateResponse: - """ - Create a package that defines a set of reusable, time-relative contract terms - that can be used across cohorts of customers. Packages provide an abstraction - layer on top of rate cards to provide an easy way to provision customers with - standard pricing. - - ### **Use this endpoint to:** - - - Model standard pay-as-you-go pricing packages that can be easily reused across - customers - - Define standardized contract terms and discounting for sales-led motions - - Set aliases for the package to facilitate easy package transition. Aliases are - human-readable names that you can use in the place of the id of the package - when provisioning a customer’s contract. By using an alias, you can easily - create a contract and provision a customer by choosing the “Starter Plan” - package, without storing the package ID in your internal systems. This is - helpful when launching terms for a package, as you can create a new package - with the “Starter Plan” alias scheduled to be assigned without updating your - provisioning code. - - ### Key input fields: - - - `starting_at_offset`: Starting date relative to contract start. Generates the - `starting_at` date when a contract is provisioned using a package. - - `duration`: Duration starting from `starting_at_offset`. Generates the - `ending_before` date when a contract is provisioned using a package. - - `date_offset`: Date relative to contract start. Used for point-in-time dates - without a duration. - - `aliases`: Human-readable name to use when provisioning contracts with a - package. - - ### Usage guidelines: - - - Use packages for standard self-serve use cases where customers have consistent - terms. For customers with negotiated custom contract terms, use the - `createContract` endpoint for maximum flexibility. - - Billing provider configuration can be set when creating a package by using - `billing_provider` and `delivery_method`. To provision a customer successfully - with a package, the customer must have one and only one billing provider - configuration that matches the billing provider configuration set on the - package. - - A package alias can only be used by one package at a time. If you create a new - package with an alias that is already in use by another package, the original - package’s alias schedule will be updated. The alias will reference the package - to which it was most recently assigned. - - Terms can only be specified using times relative to the contract start date. - Supported granularities are: `days`, `weeks`, `months`, `years` - - Packages cannot be edited once created. Use the rate card to easily add new - rates across all of your customers or make direct edits to a contract after - provisioning with a package. Edited contracts will still be associated with - the package used during provisioning. - - Args: - aliases: Reference this alias when creating a contract. If the same alias is assigned to - multiple packages, it will reference the package to which it was most recently - assigned. It is not exposed to end customers. - - multiplier_override_prioritization: Defaults to LOWEST_MULTIPLIER, which applies the greatest discount to list - prices automatically. EXPLICIT prioritization requires specifying priorities for - each multiplier; the one with the lowest priority value will be prioritized - first. If tiered overrides are used, prioritization must be explicit. - - rate_card_alias: Selects the rate card linked to the specified alias as of the contract's start - date. - - scheduled_charges_on_usage_invoices: Determines which scheduled and commit charges to consolidate onto the Contract's - usage invoice. The charge's `timestamp` must match the usage invoice's - `ending_before` date for consolidation to occur. This field cannot be modified - after a Contract has been created. If this field is omitted, charges will appear - on a separate invoice from usage charges. - - uniqueness_key: Prevents the creation of duplicates. If a request to create a record is made - with a previously used uniqueness key, a new record will not be created and the - request will fail with a 409 error. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/packages/create", - body=maybe_transform( - { - "name": name, - "aliases": aliases, - "billing_anchor_date": billing_anchor_date, - "billing_provider": billing_provider, - "commits": commits, - "contract_name": contract_name, - "credits": credits, - "delivery_method": delivery_method, - "duration": duration, - "multiplier_override_prioritization": multiplier_override_prioritization, - "net_payment_terms_days": net_payment_terms_days, - "overrides": overrides, - "prepaid_balance_threshold_configuration": prepaid_balance_threshold_configuration, - "rate_card_alias": rate_card_alias, - "rate_card_id": rate_card_id, - "recurring_commits": recurring_commits, - "recurring_credits": recurring_credits, - "scheduled_charges": scheduled_charges, - "scheduled_charges_on_usage_invoices": scheduled_charges_on_usage_invoices, - "spend_threshold_configuration": spend_threshold_configuration, - "subscriptions": subscriptions, - "uniqueness_key": uniqueness_key, - "usage_statement_schedule": usage_statement_schedule, - }, - package_create_params.PackageCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=PackageCreateResponse, - ) - - def retrieve( - self, - *, - package_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> PackageRetrieveResponse: - """ - Gets the details for a specific package, including name, aliases, duration, and - terms. Use this endpoint to understand a package’s alias schedule, or display a - specific package’s details to end customers. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/packages/get", - body=maybe_transform({"package_id": package_id}, package_retrieve_params.PackageRetrieveParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=PackageRetrieveResponse, - ) - - def list( - self, - *, - limit: int | Omit = omit, - next_page: str | Omit = omit, - archive_filter: Literal["ARCHIVED", "NOT_ARCHIVED", "ALL"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[PackageListResponse]: - """Lists all packages with details including name, aliases, duration, and terms. - - To - view contracts on a specific package, use the `listContractsOnPackage` endpoint. - - Args: - limit: The maximum number of packages to return. Defaults to 10. - - next_page: Cursor that indicates where the next page of results should start. - - archive_filter: Filter packages by archived status. Defaults to NOT_ARCHIVED. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/packages/list", - page=SyncCursorPage[PackageListResponse], - body=maybe_transform({"archive_filter": archive_filter}, package_list_params.PackageListParams), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - package_list_params.PackageListParams, - ), - ), - model=PackageListResponse, - method="post", - ) - - def archive( - self, - *, - package_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> PackageArchiveResponse: - """Archive a package. - - Archived packages cannot be used to create new contracts. - However, existing contracts associated with the package will continue to - function as normal. Once you archive a package, you can still retrieve it in the - UI and API, but you cannot unarchive it. - - Args: - package_id: ID of the package to archive - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/packages/archive", - body=maybe_transform({"package_id": package_id}, package_archive_params.PackageArchiveParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=PackageArchiveResponse, - ) - - def list_contracts_on_package( - self, - *, - package_id: str, - limit: int | Omit = omit, - next_page: str | Omit = omit, - covering_date: Union[str, datetime] | Omit = omit, - include_archived: bool | Omit = omit, - starting_at: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[PackageListContractsOnPackageResponse]: - """ - For a given package, returns all contract IDs and customer IDs associated with - the package over a specific time period. - - ### Use this endpoint to: - - - Understand which customers are provisioned on a package at any given time for - internal cohort management - - Manage customer migrations to a new package. For example, to migrate all - active customers to a new package, call this endpoint, end contracts, and - provision customers on a new package. - - ### **Usage guidelines:** - - Use the **`starting_at`**, **`covering_date`**, - and **`include_archived`** parameters to filter the list of returned contracts. - For example, to list only currently active contracts, - pass **`covering_date`** equal to the current time. - - Args: - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - covering_date: Optional RFC 3339 timestamp. Only include contracts active on the provided date. - This cannot be provided if starting_at filter is provided. - - include_archived: Default false. Determines whether to include archived contracts in the results - - starting_at: Optional RFC 3339 timestamp. Only include contracts that started on or after - this date. This cannot be provided if covering_date filter is provided. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/packages/listContractsOnPackage", - page=SyncCursorPage[PackageListContractsOnPackageResponse], - body=maybe_transform( - { - "package_id": package_id, - "covering_date": covering_date, - "include_archived": include_archived, - "starting_at": starting_at, - }, - package_list_contracts_on_package_params.PackageListContractsOnPackageParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - package_list_contracts_on_package_params.PackageListContractsOnPackageParams, - ), - ), - model=PackageListContractsOnPackageResponse, - method="post", - ) - - -class AsyncPackagesResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncPackagesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncPackagesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncPackagesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncPackagesResourceWithStreamingResponse(self) - - async def create( - self, - *, - name: str, - aliases: Iterable[package_create_params.Alias] | Omit = omit, - billing_anchor_date: Literal["contract_start_date", "first_billing_period"] | Omit = omit, - billing_provider: Literal["aws_marketplace", "azure_marketplace", "gcp_marketplace", "stripe", "netsuite"] - | Omit = omit, - commits: Iterable[package_create_params.Commit] | Omit = omit, - contract_name: str | Omit = omit, - credits: Iterable[package_create_params.Credit] | Omit = omit, - delivery_method: Literal["direct_to_billing_provider", "aws_sqs", "tackle", "aws_sns"] | Omit = omit, - duration: package_create_params.Duration | Omit = omit, - multiplier_override_prioritization: Literal["LOWEST_MULTIPLIER", "EXPLICIT"] | Omit = omit, - net_payment_terms_days: float | Omit = omit, - overrides: Iterable[package_create_params.Override] | Omit = omit, - prepaid_balance_threshold_configuration: PrepaidBalanceThresholdConfiguration | Omit = omit, - rate_card_alias: str | Omit = omit, - rate_card_id: str | Omit = omit, - recurring_commits: Iterable[package_create_params.RecurringCommit] | Omit = omit, - recurring_credits: Iterable[package_create_params.RecurringCredit] | Omit = omit, - scheduled_charges: Iterable[package_create_params.ScheduledCharge] | Omit = omit, - scheduled_charges_on_usage_invoices: Literal["ALL"] | Omit = omit, - spend_threshold_configuration: SpendThresholdConfiguration | Omit = omit, - subscriptions: Iterable[package_create_params.Subscription] | Omit = omit, - uniqueness_key: str | Omit = omit, - usage_statement_schedule: package_create_params.UsageStatementSchedule | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> PackageCreateResponse: - """ - Create a package that defines a set of reusable, time-relative contract terms - that can be used across cohorts of customers. Packages provide an abstraction - layer on top of rate cards to provide an easy way to provision customers with - standard pricing. - - ### **Use this endpoint to:** - - - Model standard pay-as-you-go pricing packages that can be easily reused across - customers - - Define standardized contract terms and discounting for sales-led motions - - Set aliases for the package to facilitate easy package transition. Aliases are - human-readable names that you can use in the place of the id of the package - when provisioning a customer’s contract. By using an alias, you can easily - create a contract and provision a customer by choosing the “Starter Plan” - package, without storing the package ID in your internal systems. This is - helpful when launching terms for a package, as you can create a new package - with the “Starter Plan” alias scheduled to be assigned without updating your - provisioning code. - - ### Key input fields: - - - `starting_at_offset`: Starting date relative to contract start. Generates the - `starting_at` date when a contract is provisioned using a package. - - `duration`: Duration starting from `starting_at_offset`. Generates the - `ending_before` date when a contract is provisioned using a package. - - `date_offset`: Date relative to contract start. Used for point-in-time dates - without a duration. - - `aliases`: Human-readable name to use when provisioning contracts with a - package. - - ### Usage guidelines: - - - Use packages for standard self-serve use cases where customers have consistent - terms. For customers with negotiated custom contract terms, use the - `createContract` endpoint for maximum flexibility. - - Billing provider configuration can be set when creating a package by using - `billing_provider` and `delivery_method`. To provision a customer successfully - with a package, the customer must have one and only one billing provider - configuration that matches the billing provider configuration set on the - package. - - A package alias can only be used by one package at a time. If you create a new - package with an alias that is already in use by another package, the original - package’s alias schedule will be updated. The alias will reference the package - to which it was most recently assigned. - - Terms can only be specified using times relative to the contract start date. - Supported granularities are: `days`, `weeks`, `months`, `years` - - Packages cannot be edited once created. Use the rate card to easily add new - rates across all of your customers or make direct edits to a contract after - provisioning with a package. Edited contracts will still be associated with - the package used during provisioning. - - Args: - aliases: Reference this alias when creating a contract. If the same alias is assigned to - multiple packages, it will reference the package to which it was most recently - assigned. It is not exposed to end customers. - - multiplier_override_prioritization: Defaults to LOWEST_MULTIPLIER, which applies the greatest discount to list - prices automatically. EXPLICIT prioritization requires specifying priorities for - each multiplier; the one with the lowest priority value will be prioritized - first. If tiered overrides are used, prioritization must be explicit. - - rate_card_alias: Selects the rate card linked to the specified alias as of the contract's start - date. - - scheduled_charges_on_usage_invoices: Determines which scheduled and commit charges to consolidate onto the Contract's - usage invoice. The charge's `timestamp` must match the usage invoice's - `ending_before` date for consolidation to occur. This field cannot be modified - after a Contract has been created. If this field is omitted, charges will appear - on a separate invoice from usage charges. - - uniqueness_key: Prevents the creation of duplicates. If a request to create a record is made - with a previously used uniqueness key, a new record will not be created and the - request will fail with a 409 error. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/packages/create", - body=await async_maybe_transform( - { - "name": name, - "aliases": aliases, - "billing_anchor_date": billing_anchor_date, - "billing_provider": billing_provider, - "commits": commits, - "contract_name": contract_name, - "credits": credits, - "delivery_method": delivery_method, - "duration": duration, - "multiplier_override_prioritization": multiplier_override_prioritization, - "net_payment_terms_days": net_payment_terms_days, - "overrides": overrides, - "prepaid_balance_threshold_configuration": prepaid_balance_threshold_configuration, - "rate_card_alias": rate_card_alias, - "rate_card_id": rate_card_id, - "recurring_commits": recurring_commits, - "recurring_credits": recurring_credits, - "scheduled_charges": scheduled_charges, - "scheduled_charges_on_usage_invoices": scheduled_charges_on_usage_invoices, - "spend_threshold_configuration": spend_threshold_configuration, - "subscriptions": subscriptions, - "uniqueness_key": uniqueness_key, - "usage_statement_schedule": usage_statement_schedule, - }, - package_create_params.PackageCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=PackageCreateResponse, - ) - - async def retrieve( - self, - *, - package_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> PackageRetrieveResponse: - """ - Gets the details for a specific package, including name, aliases, duration, and - terms. Use this endpoint to understand a package’s alias schedule, or display a - specific package’s details to end customers. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/packages/get", - body=await async_maybe_transform({"package_id": package_id}, package_retrieve_params.PackageRetrieveParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=PackageRetrieveResponse, - ) - - def list( - self, - *, - limit: int | Omit = omit, - next_page: str | Omit = omit, - archive_filter: Literal["ARCHIVED", "NOT_ARCHIVED", "ALL"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[PackageListResponse, AsyncCursorPage[PackageListResponse]]: - """Lists all packages with details including name, aliases, duration, and terms. - - To - view contracts on a specific package, use the `listContractsOnPackage` endpoint. - - Args: - limit: The maximum number of packages to return. Defaults to 10. - - next_page: Cursor that indicates where the next page of results should start. - - archive_filter: Filter packages by archived status. Defaults to NOT_ARCHIVED. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/packages/list", - page=AsyncCursorPage[PackageListResponse], - body=maybe_transform({"archive_filter": archive_filter}, package_list_params.PackageListParams), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - package_list_params.PackageListParams, - ), - ), - model=PackageListResponse, - method="post", - ) - - async def archive( - self, - *, - package_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> PackageArchiveResponse: - """Archive a package. - - Archived packages cannot be used to create new contracts. - However, existing contracts associated with the package will continue to - function as normal. Once you archive a package, you can still retrieve it in the - UI and API, but you cannot unarchive it. - - Args: - package_id: ID of the package to archive - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/packages/archive", - body=await async_maybe_transform({"package_id": package_id}, package_archive_params.PackageArchiveParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=PackageArchiveResponse, - ) - - def list_contracts_on_package( - self, - *, - package_id: str, - limit: int | Omit = omit, - next_page: str | Omit = omit, - covering_date: Union[str, datetime] | Omit = omit, - include_archived: bool | Omit = omit, - starting_at: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[PackageListContractsOnPackageResponse, AsyncCursorPage[PackageListContractsOnPackageResponse]]: - """ - For a given package, returns all contract IDs and customer IDs associated with - the package over a specific time period. - - ### Use this endpoint to: - - - Understand which customers are provisioned on a package at any given time for - internal cohort management - - Manage customer migrations to a new package. For example, to migrate all - active customers to a new package, call this endpoint, end contracts, and - provision customers on a new package. - - ### **Usage guidelines:** - - Use the **`starting_at`**, **`covering_date`**, - and **`include_archived`** parameters to filter the list of returned contracts. - For example, to list only currently active contracts, - pass **`covering_date`** equal to the current time. - - Args: - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - covering_date: Optional RFC 3339 timestamp. Only include contracts active on the provided date. - This cannot be provided if starting_at filter is provided. - - include_archived: Default false. Determines whether to include archived contracts in the results - - starting_at: Optional RFC 3339 timestamp. Only include contracts that started on or after - this date. This cannot be provided if covering_date filter is provided. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/packages/listContractsOnPackage", - page=AsyncCursorPage[PackageListContractsOnPackageResponse], - body=maybe_transform( - { - "package_id": package_id, - "covering_date": covering_date, - "include_archived": include_archived, - "starting_at": starting_at, - }, - package_list_contracts_on_package_params.PackageListContractsOnPackageParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - package_list_contracts_on_package_params.PackageListContractsOnPackageParams, - ), - ), - model=PackageListContractsOnPackageResponse, - method="post", - ) - - -class PackagesResourceWithRawResponse: - def __init__(self, packages: PackagesResource) -> None: - self._packages = packages - - self.create = to_raw_response_wrapper( - packages.create, - ) - self.retrieve = to_raw_response_wrapper( - packages.retrieve, - ) - self.list = to_raw_response_wrapper( - packages.list, - ) - self.archive = to_raw_response_wrapper( - packages.archive, - ) - self.list_contracts_on_package = to_raw_response_wrapper( - packages.list_contracts_on_package, - ) - - -class AsyncPackagesResourceWithRawResponse: - def __init__(self, packages: AsyncPackagesResource) -> None: - self._packages = packages - - self.create = async_to_raw_response_wrapper( - packages.create, - ) - self.retrieve = async_to_raw_response_wrapper( - packages.retrieve, - ) - self.list = async_to_raw_response_wrapper( - packages.list, - ) - self.archive = async_to_raw_response_wrapper( - packages.archive, - ) - self.list_contracts_on_package = async_to_raw_response_wrapper( - packages.list_contracts_on_package, - ) - - -class PackagesResourceWithStreamingResponse: - def __init__(self, packages: PackagesResource) -> None: - self._packages = packages - - self.create = to_streamed_response_wrapper( - packages.create, - ) - self.retrieve = to_streamed_response_wrapper( - packages.retrieve, - ) - self.list = to_streamed_response_wrapper( - packages.list, - ) - self.archive = to_streamed_response_wrapper( - packages.archive, - ) - self.list_contracts_on_package = to_streamed_response_wrapper( - packages.list_contracts_on_package, - ) - - -class AsyncPackagesResourceWithStreamingResponse: - def __init__(self, packages: AsyncPackagesResource) -> None: - self._packages = packages - - self.create = async_to_streamed_response_wrapper( - packages.create, - ) - self.retrieve = async_to_streamed_response_wrapper( - packages.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - packages.list, - ) - self.archive = async_to_streamed_response_wrapper( - packages.archive, - ) - self.list_contracts_on_package = async_to_streamed_response_wrapper( - packages.list_contracts_on_package, - ) diff --git a/src/metronome/resources/v1/payments.py b/src/metronome/resources/v1/payments.py deleted file mode 100644 index d53ed34f0..000000000 --- a/src/metronome/resources/v1/payments.py +++ /dev/null @@ -1,409 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List - -import httpx - -from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ...types.v1 import payment_list_params, payment_cancel_params, payment_attempt_params -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ...pagination import SyncBodyCursorPage, AsyncBodyCursorPage -from ..._base_client import AsyncPaginator, make_request_options -from ...types.v1.payment import Payment -from ...types.v1.payment_status import PaymentStatus -from ...types.v1.payment_cancel_response import PaymentCancelResponse -from ...types.v1.payment_attempt_response import PaymentAttemptResponse - -__all__ = ["PaymentsResource", "AsyncPaymentsResource"] - - -class PaymentsResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> PaymentsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return PaymentsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> PaymentsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return PaymentsResourceWithStreamingResponse(self) - - def list( - self, - *, - customer_id: str, - invoice_id: str, - limit: int | Omit = omit, - next_page: str | Omit = omit, - statuses: List[PaymentStatus] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncBodyCursorPage[Payment]: - """ - Fetch all payment attempts for the given invoice. - - Args: - limit: The maximum number of payments to return. Defaults to 25. - - next_page: The next page token from a previous response. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/payments/list", - page=SyncBodyCursorPage[Payment], - body=maybe_transform( - { - "customer_id": customer_id, - "invoice_id": invoice_id, - "limit": limit, - "next_page": next_page, - "statuses": statuses, - }, - payment_list_params.PaymentListParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - model=Payment, - method="post", - ) - - def attempt( - self, - *, - customer_id: str, - invoice_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> PaymentAttemptResponse: - """ - Trigger a new attempt by canceling any existing attempts for this invoice and - creating a new Payment. This will trigger another attempt to charge the - Customer's configured Payment Gateway. Payment can only be attempted if all of - the following are true: - - - The Metronome Invoice is finalized - - PLG Invoicing is configured for the Customer - - You cannot attempt payments for invoices that have already been `paid` or - `voided`. - - Attempting to payment on an ineligible Invoice or Customer will result in a - `400` response. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/payments/attempt", - body=maybe_transform( - { - "customer_id": customer_id, - "invoice_id": invoice_id, - }, - payment_attempt_params.PaymentAttemptParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=PaymentAttemptResponse, - ) - - def cancel( - self, - *, - customer_id: str, - invoice_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> PaymentCancelResponse: - """ - Cancel an existing payment attempt for an invoice. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/payments/cancel", - body=maybe_transform( - { - "customer_id": customer_id, - "invoice_id": invoice_id, - }, - payment_cancel_params.PaymentCancelParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=PaymentCancelResponse, - ) - - -class AsyncPaymentsResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncPaymentsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncPaymentsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncPaymentsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncPaymentsResourceWithStreamingResponse(self) - - def list( - self, - *, - customer_id: str, - invoice_id: str, - limit: int | Omit = omit, - next_page: str | Omit = omit, - statuses: List[PaymentStatus] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[Payment, AsyncBodyCursorPage[Payment]]: - """ - Fetch all payment attempts for the given invoice. - - Args: - limit: The maximum number of payments to return. Defaults to 25. - - next_page: The next page token from a previous response. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/payments/list", - page=AsyncBodyCursorPage[Payment], - body=maybe_transform( - { - "customer_id": customer_id, - "invoice_id": invoice_id, - "limit": limit, - "next_page": next_page, - "statuses": statuses, - }, - payment_list_params.PaymentListParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - model=Payment, - method="post", - ) - - async def attempt( - self, - *, - customer_id: str, - invoice_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> PaymentAttemptResponse: - """ - Trigger a new attempt by canceling any existing attempts for this invoice and - creating a new Payment. This will trigger another attempt to charge the - Customer's configured Payment Gateway. Payment can only be attempted if all of - the following are true: - - - The Metronome Invoice is finalized - - PLG Invoicing is configured for the Customer - - You cannot attempt payments for invoices that have already been `paid` or - `voided`. - - Attempting to payment on an ineligible Invoice or Customer will result in a - `400` response. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/payments/attempt", - body=await async_maybe_transform( - { - "customer_id": customer_id, - "invoice_id": invoice_id, - }, - payment_attempt_params.PaymentAttemptParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=PaymentAttemptResponse, - ) - - async def cancel( - self, - *, - customer_id: str, - invoice_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> PaymentCancelResponse: - """ - Cancel an existing payment attempt for an invoice. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/payments/cancel", - body=await async_maybe_transform( - { - "customer_id": customer_id, - "invoice_id": invoice_id, - }, - payment_cancel_params.PaymentCancelParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=PaymentCancelResponse, - ) - - -class PaymentsResourceWithRawResponse: - def __init__(self, payments: PaymentsResource) -> None: - self._payments = payments - - self.list = to_raw_response_wrapper( - payments.list, - ) - self.attempt = to_raw_response_wrapper( - payments.attempt, - ) - self.cancel = to_raw_response_wrapper( - payments.cancel, - ) - - -class AsyncPaymentsResourceWithRawResponse: - def __init__(self, payments: AsyncPaymentsResource) -> None: - self._payments = payments - - self.list = async_to_raw_response_wrapper( - payments.list, - ) - self.attempt = async_to_raw_response_wrapper( - payments.attempt, - ) - self.cancel = async_to_raw_response_wrapper( - payments.cancel, - ) - - -class PaymentsResourceWithStreamingResponse: - def __init__(self, payments: PaymentsResource) -> None: - self._payments = payments - - self.list = to_streamed_response_wrapper( - payments.list, - ) - self.attempt = to_streamed_response_wrapper( - payments.attempt, - ) - self.cancel = to_streamed_response_wrapper( - payments.cancel, - ) - - -class AsyncPaymentsResourceWithStreamingResponse: - def __init__(self, payments: AsyncPaymentsResource) -> None: - self._payments = payments - - self.list = async_to_streamed_response_wrapper( - payments.list, - ) - self.attempt = async_to_streamed_response_wrapper( - payments.attempt, - ) - self.cancel = async_to_streamed_response_wrapper( - payments.cancel, - ) diff --git a/src/metronome/resources/v1/plans.py b/src/metronome/resources/v1/plans.py deleted file mode 100644 index 490f9b2cb..000000000 --- a/src/metronome/resources/v1/plans.py +++ /dev/null @@ -1,549 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal - -import httpx - -from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform -from ..._compat import cached_property -from ...types.v1 import plan_list_params, plan_list_charges_params, plan_list_customers_params -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ...pagination import SyncCursorPage, AsyncCursorPage -from ..._base_client import AsyncPaginator, make_request_options -from ...types.v1.plan_list_response import PlanListResponse -from ...types.v1.plan_get_details_response import PlanGetDetailsResponse -from ...types.v1.plan_list_charges_response import PlanListChargesResponse -from ...types.v1.plan_list_customers_response import PlanListCustomersResponse - -__all__ = ["PlansResource", "AsyncPlansResource"] - - -class PlansResource(SyncAPIResource): - """ - [Plans](https://docs.metronome.com/pricing-and-packaging/create-plans/) determine the base pricing for a customer. Use these endpoints to add a plan to a customer, end a customer plan, retrieve plans, and retrieve plan details. Create plans in the [Metronome app](https://app.metronome.com/plans). - """ - - @cached_property - def with_raw_response(self) -> PlansResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return PlansResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> PlansResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return PlansResourceWithStreamingResponse(self) - - def list( - self, - *, - limit: int | Omit = omit, - next_page: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[PlanListResponse]: - """List all available plans. - - This is a Plans (deprecated) endpoint. New clients - should implement using Contracts. - - Args: - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/plans", - page=SyncCursorPage[PlanListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - plan_list_params.PlanListParams, - ), - ), - model=PlanListResponse, - ) - - def get_details( - self, - *, - plan_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> PlanGetDetailsResponse: - """Fetch high level details of a specific plan. - - This is a Plans (deprecated) - endpoint. New clients should implement using Contracts. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not plan_id: - raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}") - return self._get( - f"/v1/planDetails/{plan_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=PlanGetDetailsResponse, - ) - - def list_charges( - self, - *, - plan_id: str, - limit: int | Omit = omit, - next_page: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[PlanListChargesResponse]: - """Fetches a list of charges of a specific plan. - - This is a Plans (deprecated) - endpoint. New clients should implement using Contracts. - - Args: - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not plan_id: - raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}") - return self._get_api_list( - f"/v1/planDetails/{plan_id}/charges", - page=SyncCursorPage[PlanListChargesResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - plan_list_charges_params.PlanListChargesParams, - ), - ), - model=PlanListChargesResponse, - ) - - def list_customers( - self, - *, - plan_id: str, - limit: int | Omit = omit, - next_page: str | Omit = omit, - status: Literal["all", "active", "ended", "upcoming"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[PlanListCustomersResponse]: - """ - Fetches a list of customers on a specific plan (by default, only currently - active plans are included). This is a Plans (deprecated) endpoint. New clients - should implement using Contracts. - - Args: - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - status: Status of customers on a given plan. Defaults to `active`. - - - `all` - Return current, past, and upcoming customers of the plan. - - `active` - Return current customers of the plan. - - `ended` - Return past customers of the plan. - - `upcoming` - Return upcoming customers of the plan. - - Multiple statuses can be OR'd together using commas, e.g. `active,ended`. - **Note:** `ended,upcoming` combination is not yet supported. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not plan_id: - raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}") - return self._get_api_list( - f"/v1/planDetails/{plan_id}/customers", - page=SyncCursorPage[PlanListCustomersResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - "status": status, - }, - plan_list_customers_params.PlanListCustomersParams, - ), - ), - model=PlanListCustomersResponse, - ) - - -class AsyncPlansResource(AsyncAPIResource): - """ - [Plans](https://docs.metronome.com/pricing-and-packaging/create-plans/) determine the base pricing for a customer. Use these endpoints to add a plan to a customer, end a customer plan, retrieve plans, and retrieve plan details. Create plans in the [Metronome app](https://app.metronome.com/plans). - """ - - @cached_property - def with_raw_response(self) -> AsyncPlansResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncPlansResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncPlansResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncPlansResourceWithStreamingResponse(self) - - def list( - self, - *, - limit: int | Omit = omit, - next_page: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[PlanListResponse, AsyncCursorPage[PlanListResponse]]: - """List all available plans. - - This is a Plans (deprecated) endpoint. New clients - should implement using Contracts. - - Args: - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/plans", - page=AsyncCursorPage[PlanListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - plan_list_params.PlanListParams, - ), - ), - model=PlanListResponse, - ) - - async def get_details( - self, - *, - plan_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> PlanGetDetailsResponse: - """Fetch high level details of a specific plan. - - This is a Plans (deprecated) - endpoint. New clients should implement using Contracts. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not plan_id: - raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}") - return await self._get( - f"/v1/planDetails/{plan_id}", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=PlanGetDetailsResponse, - ) - - def list_charges( - self, - *, - plan_id: str, - limit: int | Omit = omit, - next_page: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[PlanListChargesResponse, AsyncCursorPage[PlanListChargesResponse]]: - """Fetches a list of charges of a specific plan. - - This is a Plans (deprecated) - endpoint. New clients should implement using Contracts. - - Args: - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not plan_id: - raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}") - return self._get_api_list( - f"/v1/planDetails/{plan_id}/charges", - page=AsyncCursorPage[PlanListChargesResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - plan_list_charges_params.PlanListChargesParams, - ), - ), - model=PlanListChargesResponse, - ) - - def list_customers( - self, - *, - plan_id: str, - limit: int | Omit = omit, - next_page: str | Omit = omit, - status: Literal["all", "active", "ended", "upcoming"] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[PlanListCustomersResponse, AsyncCursorPage[PlanListCustomersResponse]]: - """ - Fetches a list of customers on a specific plan (by default, only currently - active plans are included). This is a Plans (deprecated) endpoint. New clients - should implement using Contracts. - - Args: - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - status: Status of customers on a given plan. Defaults to `active`. - - - `all` - Return current, past, and upcoming customers of the plan. - - `active` - Return current customers of the plan. - - `ended` - Return past customers of the plan. - - `upcoming` - Return upcoming customers of the plan. - - Multiple statuses can be OR'd together using commas, e.g. `active,ended`. - **Note:** `ended,upcoming` combination is not yet supported. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - if not plan_id: - raise ValueError(f"Expected a non-empty value for `plan_id` but received {plan_id!r}") - return self._get_api_list( - f"/v1/planDetails/{plan_id}/customers", - page=AsyncCursorPage[PlanListCustomersResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - "status": status, - }, - plan_list_customers_params.PlanListCustomersParams, - ), - ), - model=PlanListCustomersResponse, - ) - - -class PlansResourceWithRawResponse: - def __init__(self, plans: PlansResource) -> None: - self._plans = plans - - self.list = to_raw_response_wrapper( - plans.list, - ) - self.get_details = to_raw_response_wrapper( - plans.get_details, - ) - self.list_charges = to_raw_response_wrapper( - plans.list_charges, - ) - self.list_customers = to_raw_response_wrapper( - plans.list_customers, - ) - - -class AsyncPlansResourceWithRawResponse: - def __init__(self, plans: AsyncPlansResource) -> None: - self._plans = plans - - self.list = async_to_raw_response_wrapper( - plans.list, - ) - self.get_details = async_to_raw_response_wrapper( - plans.get_details, - ) - self.list_charges = async_to_raw_response_wrapper( - plans.list_charges, - ) - self.list_customers = async_to_raw_response_wrapper( - plans.list_customers, - ) - - -class PlansResourceWithStreamingResponse: - def __init__(self, plans: PlansResource) -> None: - self._plans = plans - - self.list = to_streamed_response_wrapper( - plans.list, - ) - self.get_details = to_streamed_response_wrapper( - plans.get_details, - ) - self.list_charges = to_streamed_response_wrapper( - plans.list_charges, - ) - self.list_customers = to_streamed_response_wrapper( - plans.list_customers, - ) - - -class AsyncPlansResourceWithStreamingResponse: - def __init__(self, plans: AsyncPlansResource) -> None: - self._plans = plans - - self.list = async_to_streamed_response_wrapper( - plans.list, - ) - self.get_details = async_to_streamed_response_wrapper( - plans.get_details, - ) - self.list_charges = async_to_streamed_response_wrapper( - plans.list_charges, - ) - self.list_customers = async_to_streamed_response_wrapper( - plans.list_customers, - ) diff --git a/src/metronome/resources/v1/pricing_units.py b/src/metronome/resources/v1/pricing_units.py deleted file mode 100644 index 23de99850..000000000 --- a/src/metronome/resources/v1/pricing_units.py +++ /dev/null @@ -1,214 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import httpx - -from ..._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ..._utils import maybe_transform -from ..._compat import cached_property -from ...types.v1 import pricing_unit_list_params -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ...pagination import SyncCursorPage, AsyncCursorPage -from ..._base_client import AsyncPaginator, make_request_options -from ...types.v1.pricing_unit_list_response import PricingUnitListResponse - -__all__ = ["PricingUnitsResource", "AsyncPricingUnitsResource"] - - -class PricingUnitsResource(SyncAPIResource): - """ - Use these endpoints to configure a billing API key, a webhook secret, or invoice finalization behavior. - """ - - @cached_property - def with_raw_response(self) -> PricingUnitsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return PricingUnitsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> PricingUnitsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return PricingUnitsResourceWithStreamingResponse(self) - - def list( - self, - *, - limit: int | Omit = omit, - next_page: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[PricingUnitListResponse]: - """List all pricing units. - - All fiat currency types (for example, USD or GBP) will - be included, as well as any custom pricing units that were configured. Custom - pricing units can be used to charge for usage in a non-fiat pricing unit, for - example AI credits. - - Note: The USD (cents) pricing unit is 2714e483-4ff1-48e4-9e25-ac732e8f24f2. - - Args: - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/credit-types/list", - page=SyncCursorPage[PricingUnitListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - pricing_unit_list_params.PricingUnitListParams, - ), - ), - model=PricingUnitListResponse, - ) - - -class AsyncPricingUnitsResource(AsyncAPIResource): - """ - Use these endpoints to configure a billing API key, a webhook secret, or invoice finalization behavior. - """ - - @cached_property - def with_raw_response(self) -> AsyncPricingUnitsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncPricingUnitsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncPricingUnitsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncPricingUnitsResourceWithStreamingResponse(self) - - def list( - self, - *, - limit: int | Omit = omit, - next_page: str | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[PricingUnitListResponse, AsyncCursorPage[PricingUnitListResponse]]: - """List all pricing units. - - All fiat currency types (for example, USD or GBP) will - be included, as well as any custom pricing units that were configured. Custom - pricing units can be used to charge for usage in a non-fiat pricing unit, for - example AI credits. - - Note: The USD (cents) pricing unit is 2714e483-4ff1-48e4-9e25-ac732e8f24f2. - - Args: - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/credit-types/list", - page=AsyncCursorPage[PricingUnitListResponse], - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - pricing_unit_list_params.PricingUnitListParams, - ), - ), - model=PricingUnitListResponse, - ) - - -class PricingUnitsResourceWithRawResponse: - def __init__(self, pricing_units: PricingUnitsResource) -> None: - self._pricing_units = pricing_units - - self.list = to_raw_response_wrapper( - pricing_units.list, - ) - - -class AsyncPricingUnitsResourceWithRawResponse: - def __init__(self, pricing_units: AsyncPricingUnitsResource) -> None: - self._pricing_units = pricing_units - - self.list = async_to_raw_response_wrapper( - pricing_units.list, - ) - - -class PricingUnitsResourceWithStreamingResponse: - def __init__(self, pricing_units: PricingUnitsResource) -> None: - self._pricing_units = pricing_units - - self.list = to_streamed_response_wrapper( - pricing_units.list, - ) - - -class AsyncPricingUnitsResourceWithStreamingResponse: - def __init__(self, pricing_units: AsyncPricingUnitsResource) -> None: - self._pricing_units = pricing_units - - self.list = async_to_streamed_response_wrapper( - pricing_units.list, - ) diff --git a/src/metronome/resources/v1/services.py b/src/metronome/resources/v1/services.py deleted file mode 100644 index 4e090e3b4..000000000 --- a/src/metronome/resources/v1/services.py +++ /dev/null @@ -1,157 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -import httpx - -from ..._types import Body, Query, Headers, NotGiven, not_given -from ..._compat import cached_property -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ..._base_client import make_request_options -from ...types.v1.service_list_response import ServiceListResponse - -__all__ = ["ServicesResource", "AsyncServicesResource"] - - -class ServicesResource(SyncAPIResource): - """ - [Security](https://docs.metronome.com/developer-resources/security/) endpoints allow you to retrieve security-related data. - """ - - @cached_property - def with_raw_response(self) -> ServicesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return ServicesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ServicesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return ServicesResourceWithStreamingResponse(self) - - def list( - self, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ServiceListResponse: - """ - Gets Metronome's service registry with associated IP addresses for security - allowlisting and firewall configuration. Use this endpoint to maintain an - up-to-date list of IPs that your systems should trust for Metronome - communications. Returns service names and their current IP ranges, with new IPs - typically appearing 30+ days before first use to ensure smooth allowlist - updates. - """ - return self._get( - "/v1/services", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ServiceListResponse, - ) - - -class AsyncServicesResource(AsyncAPIResource): - """ - [Security](https://docs.metronome.com/developer-resources/security/) endpoints allow you to retrieve security-related data. - """ - - @cached_property - def with_raw_response(self) -> AsyncServicesResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncServicesResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncServicesResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncServicesResourceWithStreamingResponse(self) - - async def list( - self, - *, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ServiceListResponse: - """ - Gets Metronome's service registry with associated IP addresses for security - allowlisting and firewall configuration. Use this endpoint to maintain an - up-to-date list of IPs that your systems should trust for Metronome - communications. Returns service names and their current IP ranges, with new IPs - typically appearing 30+ days before first use to ensure smooth allowlist - updates. - """ - return await self._get( - "/v1/services", - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ServiceListResponse, - ) - - -class ServicesResourceWithRawResponse: - def __init__(self, services: ServicesResource) -> None: - self._services = services - - self.list = to_raw_response_wrapper( - services.list, - ) - - -class AsyncServicesResourceWithRawResponse: - def __init__(self, services: AsyncServicesResource) -> None: - self._services = services - - self.list = async_to_raw_response_wrapper( - services.list, - ) - - -class ServicesResourceWithStreamingResponse: - def __init__(self, services: ServicesResource) -> None: - self._services = services - - self.list = to_streamed_response_wrapper( - services.list, - ) - - -class AsyncServicesResourceWithStreamingResponse: - def __init__(self, services: AsyncServicesResource) -> None: - self._services = services - - self.list = async_to_streamed_response_wrapper( - services.list, - ) diff --git a/src/metronome/resources/v1/settings/__init__.py b/src/metronome/resources/v1/settings/__init__.py deleted file mode 100644 index 296d3f8b7..000000000 --- a/src/metronome/resources/v1/settings/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .settings import ( - SettingsResource, - AsyncSettingsResource, - SettingsResourceWithRawResponse, - AsyncSettingsResourceWithRawResponse, - SettingsResourceWithStreamingResponse, - AsyncSettingsResourceWithStreamingResponse, -) -from .billing_providers import ( - BillingProvidersResource, - AsyncBillingProvidersResource, - BillingProvidersResourceWithRawResponse, - AsyncBillingProvidersResourceWithRawResponse, - BillingProvidersResourceWithStreamingResponse, - AsyncBillingProvidersResourceWithStreamingResponse, -) - -__all__ = [ - "BillingProvidersResource", - "AsyncBillingProvidersResource", - "BillingProvidersResourceWithRawResponse", - "AsyncBillingProvidersResourceWithRawResponse", - "BillingProvidersResourceWithStreamingResponse", - "AsyncBillingProvidersResourceWithStreamingResponse", - "SettingsResource", - "AsyncSettingsResource", - "SettingsResourceWithRawResponse", - "AsyncSettingsResourceWithRawResponse", - "SettingsResourceWithStreamingResponse", - "AsyncSettingsResourceWithStreamingResponse", -] diff --git a/src/metronome/resources/v1/settings/billing_providers.py b/src/metronome/resources/v1/settings/billing_providers.py deleted file mode 100644 index ab5964d51..000000000 --- a/src/metronome/resources/v1/settings/billing_providers.py +++ /dev/null @@ -1,303 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Optional -from typing_extensions import Literal - -import httpx - -from ...._types import Body, Omit, Query, Headers, NotGiven, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform -from ...._compat import cached_property -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ...._base_client import make_request_options -from ....types.v1.settings import billing_provider_list_params, billing_provider_create_params -from ....types.v1.settings.billing_provider_list_response import BillingProviderListResponse -from ....types.v1.settings.billing_provider_create_response import BillingProviderCreateResponse - -__all__ = ["BillingProvidersResource", "AsyncBillingProvidersResource"] - - -class BillingProvidersResource(SyncAPIResource): - """ - Use these endpoints to configure a billing API key, a webhook secret, or invoice finalization behavior. - """ - - @cached_property - def with_raw_response(self) -> BillingProvidersResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return BillingProvidersResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> BillingProvidersResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return BillingProvidersResourceWithStreamingResponse(self) - - def create( - self, - *, - billing_provider: Literal["aws_marketplace", "azure_marketplace", "gcp_marketplace"], - configuration: Dict[str, object], - delivery_method: Literal["direct_to_billing_provider", "aws_sqs", "aws_sns"], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> BillingProviderCreateResponse: - """Set up account-level configuration for a billing provider. - - Once configured, - individual contracts across customers can be mapped to this configuration using - the returned delivery_method_id. - - Args: - billing_provider: The billing provider set for this configuration. - - configuration: Account-level configuration for the billing provider. The structure of this - object is specific to the billing provider and delivery provider combination. - See examples below. - - delivery_method: The method to use for delivering invoices for this configuration. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/setUpBillingProvider", - body=maybe_transform( - { - "billing_provider": billing_provider, - "configuration": configuration, - "delivery_method": delivery_method, - }, - billing_provider_create_params.BillingProviderCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=BillingProviderCreateResponse, - ) - - def list( - self, - *, - next_page: Optional[str] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> BillingProviderListResponse: - """ - Lists all configured billing providers and their delivery method configurations - for your account. Returns provider details, delivery method IDs, and - configuration settings needed for mapping individual customer contracts to - billing integrations. - - Args: - next_page: The cursor to the next page of results - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/listConfiguredBillingProviders", - body=maybe_transform({"next_page": next_page}, billing_provider_list_params.BillingProviderListParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=BillingProviderListResponse, - ) - - -class AsyncBillingProvidersResource(AsyncAPIResource): - """ - Use these endpoints to configure a billing API key, a webhook secret, or invoice finalization behavior. - """ - - @cached_property - def with_raw_response(self) -> AsyncBillingProvidersResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncBillingProvidersResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncBillingProvidersResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncBillingProvidersResourceWithStreamingResponse(self) - - async def create( - self, - *, - billing_provider: Literal["aws_marketplace", "azure_marketplace", "gcp_marketplace"], - configuration: Dict[str, object], - delivery_method: Literal["direct_to_billing_provider", "aws_sqs", "aws_sns"], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> BillingProviderCreateResponse: - """Set up account-level configuration for a billing provider. - - Once configured, - individual contracts across customers can be mapped to this configuration using - the returned delivery_method_id. - - Args: - billing_provider: The billing provider set for this configuration. - - configuration: Account-level configuration for the billing provider. The structure of this - object is specific to the billing provider and delivery provider combination. - See examples below. - - delivery_method: The method to use for delivering invoices for this configuration. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/setUpBillingProvider", - body=await async_maybe_transform( - { - "billing_provider": billing_provider, - "configuration": configuration, - "delivery_method": delivery_method, - }, - billing_provider_create_params.BillingProviderCreateParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=BillingProviderCreateResponse, - ) - - async def list( - self, - *, - next_page: Optional[str] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> BillingProviderListResponse: - """ - Lists all configured billing providers and their delivery method configurations - for your account. Returns provider details, delivery method IDs, and - configuration settings needed for mapping individual customer contracts to - billing integrations. - - Args: - next_page: The cursor to the next page of results - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/listConfiguredBillingProviders", - body=await async_maybe_transform( - {"next_page": next_page}, billing_provider_list_params.BillingProviderListParams - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=BillingProviderListResponse, - ) - - -class BillingProvidersResourceWithRawResponse: - def __init__(self, billing_providers: BillingProvidersResource) -> None: - self._billing_providers = billing_providers - - self.create = to_raw_response_wrapper( - billing_providers.create, - ) - self.list = to_raw_response_wrapper( - billing_providers.list, - ) - - -class AsyncBillingProvidersResourceWithRawResponse: - def __init__(self, billing_providers: AsyncBillingProvidersResource) -> None: - self._billing_providers = billing_providers - - self.create = async_to_raw_response_wrapper( - billing_providers.create, - ) - self.list = async_to_raw_response_wrapper( - billing_providers.list, - ) - - -class BillingProvidersResourceWithStreamingResponse: - def __init__(self, billing_providers: BillingProvidersResource) -> None: - self._billing_providers = billing_providers - - self.create = to_streamed_response_wrapper( - billing_providers.create, - ) - self.list = to_streamed_response_wrapper( - billing_providers.list, - ) - - -class AsyncBillingProvidersResourceWithStreamingResponse: - def __init__(self, billing_providers: AsyncBillingProvidersResource) -> None: - self._billing_providers = billing_providers - - self.create = async_to_streamed_response_wrapper( - billing_providers.create, - ) - self.list = async_to_streamed_response_wrapper( - billing_providers.list, - ) diff --git a/src/metronome/resources/v1/settings/settings.py b/src/metronome/resources/v1/settings/settings.py deleted file mode 100644 index 5b19f11ff..000000000 --- a/src/metronome/resources/v1/settings/settings.py +++ /dev/null @@ -1,279 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal - -import httpx - -from ...._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ...._utils import maybe_transform, async_maybe_transform -from ...._compat import cached_property -from ....types.v1 import setting_upsert_avalara_credentials_params -from ...._resource import SyncAPIResource, AsyncAPIResource -from ...._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ...._base_client import make_request_options -from .billing_providers import ( - BillingProvidersResource, - AsyncBillingProvidersResource, - BillingProvidersResourceWithRawResponse, - AsyncBillingProvidersResourceWithRawResponse, - BillingProvidersResourceWithStreamingResponse, - AsyncBillingProvidersResourceWithStreamingResponse, -) -from ....types.v1.setting_upsert_avalara_credentials_response import SettingUpsertAvalaraCredentialsResponse - -__all__ = ["SettingsResource", "AsyncSettingsResource"] - - -class SettingsResource(SyncAPIResource): - """ - Use these endpoints to configure a billing API key, a webhook secret, or invoice finalization behavior. - """ - - @cached_property - def billing_providers(self) -> BillingProvidersResource: - """ - Use these endpoints to configure a billing API key, a webhook secret, or invoice finalization behavior. - """ - return BillingProvidersResource(self._client) - - @cached_property - def with_raw_response(self) -> SettingsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return SettingsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> SettingsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return SettingsResourceWithStreamingResponse(self) - - def upsert_avalara_credentials( - self, - *, - avalara_environment: Literal["PRODUCTION", "SANDBOX"], - avalara_password: str, - avalara_username: str, - delivery_method_ids: SequenceNotStr[str], - commit_transactions: bool | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SettingUpsertAvalaraCredentialsResponse: - """ - Set the Avalara credentials for some specified `delivery_method_ids`, which can - be found in the `/listConfiguredBillingProviders` response. This maps the - Avalara credentials to the appropriate billing entity. These credentials are - only used for PLG Invoicing today. - - Args: - avalara_environment: The Avalara environment to use (SANDBOX or PRODUCTION). - - avalara_password: The password for the Avalara account. - - avalara_username: The username for the Avalara account. - - delivery_method_ids: The delivery method IDs of the billing provider configurations to update, can be - found in the response of the `/listConfiguredBillingProviders` endpoint. - - commit_transactions: Commit transactions if you want Metronome tax calculations used for reporting - and tax filings. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/upsertAvalaraCredentials", - body=maybe_transform( - { - "avalara_environment": avalara_environment, - "avalara_password": avalara_password, - "avalara_username": avalara_username, - "delivery_method_ids": delivery_method_ids, - "commit_transactions": commit_transactions, - }, - setting_upsert_avalara_credentials_params.SettingUpsertAvalaraCredentialsParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=SettingUpsertAvalaraCredentialsResponse, - ) - - -class AsyncSettingsResource(AsyncAPIResource): - """ - Use these endpoints to configure a billing API key, a webhook secret, or invoice finalization behavior. - """ - - @cached_property - def billing_providers(self) -> AsyncBillingProvidersResource: - """ - Use these endpoints to configure a billing API key, a webhook secret, or invoice finalization behavior. - """ - return AsyncBillingProvidersResource(self._client) - - @cached_property - def with_raw_response(self) -> AsyncSettingsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncSettingsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncSettingsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncSettingsResourceWithStreamingResponse(self) - - async def upsert_avalara_credentials( - self, - *, - avalara_environment: Literal["PRODUCTION", "SANDBOX"], - avalara_password: str, - avalara_username: str, - delivery_method_ids: SequenceNotStr[str], - commit_transactions: bool | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SettingUpsertAvalaraCredentialsResponse: - """ - Set the Avalara credentials for some specified `delivery_method_ids`, which can - be found in the `/listConfiguredBillingProviders` response. This maps the - Avalara credentials to the appropriate billing entity. These credentials are - only used for PLG Invoicing today. - - Args: - avalara_environment: The Avalara environment to use (SANDBOX or PRODUCTION). - - avalara_password: The password for the Avalara account. - - avalara_username: The username for the Avalara account. - - delivery_method_ids: The delivery method IDs of the billing provider configurations to update, can be - found in the response of the `/listConfiguredBillingProviders` endpoint. - - commit_transactions: Commit transactions if you want Metronome tax calculations used for reporting - and tax filings. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/upsertAvalaraCredentials", - body=await async_maybe_transform( - { - "avalara_environment": avalara_environment, - "avalara_password": avalara_password, - "avalara_username": avalara_username, - "delivery_method_ids": delivery_method_ids, - "commit_transactions": commit_transactions, - }, - setting_upsert_avalara_credentials_params.SettingUpsertAvalaraCredentialsParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=SettingUpsertAvalaraCredentialsResponse, - ) - - -class SettingsResourceWithRawResponse: - def __init__(self, settings: SettingsResource) -> None: - self._settings = settings - - self.upsert_avalara_credentials = to_raw_response_wrapper( - settings.upsert_avalara_credentials, - ) - - @cached_property - def billing_providers(self) -> BillingProvidersResourceWithRawResponse: - """ - Use these endpoints to configure a billing API key, a webhook secret, or invoice finalization behavior. - """ - return BillingProvidersResourceWithRawResponse(self._settings.billing_providers) - - -class AsyncSettingsResourceWithRawResponse: - def __init__(self, settings: AsyncSettingsResource) -> None: - self._settings = settings - - self.upsert_avalara_credentials = async_to_raw_response_wrapper( - settings.upsert_avalara_credentials, - ) - - @cached_property - def billing_providers(self) -> AsyncBillingProvidersResourceWithRawResponse: - """ - Use these endpoints to configure a billing API key, a webhook secret, or invoice finalization behavior. - """ - return AsyncBillingProvidersResourceWithRawResponse(self._settings.billing_providers) - - -class SettingsResourceWithStreamingResponse: - def __init__(self, settings: SettingsResource) -> None: - self._settings = settings - - self.upsert_avalara_credentials = to_streamed_response_wrapper( - settings.upsert_avalara_credentials, - ) - - @cached_property - def billing_providers(self) -> BillingProvidersResourceWithStreamingResponse: - """ - Use these endpoints to configure a billing API key, a webhook secret, or invoice finalization behavior. - """ - return BillingProvidersResourceWithStreamingResponse(self._settings.billing_providers) - - -class AsyncSettingsResourceWithStreamingResponse: - def __init__(self, settings: AsyncSettingsResource) -> None: - self._settings = settings - - self.upsert_avalara_credentials = async_to_streamed_response_wrapper( - settings.upsert_avalara_credentials, - ) - - @cached_property - def billing_providers(self) -> AsyncBillingProvidersResourceWithStreamingResponse: - """ - Use these endpoints to configure a billing API key, a webhook secret, or invoice finalization behavior. - """ - return AsyncBillingProvidersResourceWithStreamingResponse(self._settings.billing_providers) diff --git a/src/metronome/resources/v1/usage.py b/src/metronome/resources/v1/usage.py deleted file mode 100644 index b169216d2..000000000 --- a/src/metronome/resources/v1/usage.py +++ /dev/null @@ -1,1026 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable -from datetime import datetime -from typing_extensions import Literal - -import httpx - -from ..._types import Body, Omit, Query, Headers, NoneType, NotGiven, SequenceNotStr, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ...types.v1 import usage_list_params, usage_ingest_params, usage_search_params, usage_list_with_groups_params -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ...pagination import SyncCursorPage, AsyncCursorPage, SyncCursorPageWithoutLimit, AsyncCursorPageWithoutLimit -from ..._base_client import AsyncPaginator, make_request_options -from ...types.v1.usage_list_response import UsageListResponse -from ...types.v1.usage_search_response import UsageSearchResponse -from ...types.v1.usage_list_with_groups_response import UsageListWithGroupsResponse - -__all__ = ["UsageResource", "AsyncUsageResource"] - - -class UsageResource(SyncAPIResource): - """ - [Usage events](https://docs.metronome.com/connecting-metronome/send-usage-data/) are the basis for billable metrics. Use these endpoints to send usage events to Metronome and retrieve aggregated event data. - """ - - @cached_property - def with_raw_response(self) -> UsageResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return UsageResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> UsageResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return UsageResourceWithStreamingResponse(self) - - def list( - self, - *, - ending_before: Union[str, datetime], - starting_on: Union[str, datetime], - window_size: Literal["HOUR", "DAY", "NONE"], - next_page: str | Omit = omit, - billable_metrics: Iterable[usage_list_params.BillableMetric] | Omit = omit, - customer_ids: SequenceNotStr[str] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPageWithoutLimit[UsageListResponse]: - """ - Retrieve aggregated usage data across multiple customers and billable metrics in - a single query. This batch endpoint enables you to fetch usage patterns at - scale, broken down by time windows, making it ideal for building analytics - dashboards, generating reports, and monitoring platform-wide usage trends. - - ### Use this endpoint to: - - - Generate platform-wide usage reports for internal teams - - Monitor aggregate usage trends across your entire customer base - - Create comparative usage analyses between customers or time periods - - Support capacity planning with historical usage patterns - - ### Key response fields: - - An array of `UsageBatchAggregate` objects containing: - - - `customer_id`: The customer this usage belongs to - - `billable_metric_id` and `billable_metric_name`: What was measured - - `start_timestamp` and `end_timestamp`: Time window for this data point - - `value`: Aggregated usage amount for the period - - `groups` (optional): Usage broken down by group keys with values - - `next_page`: Pagination cursor for large result sets - - ### Usage guidelines: - - - Time windows: Set `window_size` to `hour`, `day`, or `none` (entire period) - - Required parameters: Must specify `starting_on`, `ending_before`, and - `window_size` - - Filtering options: - - `customer_ids`: Limit to specific customers (omit for all customers) - - `billable_metrics`: Limit to specific metrics (omit for all metrics) - - Pagination: Use `next_page` cursor to retrieve large datasets - - Null values: Group values may be null when no usage matches that group - - Args: - window_size: A window_size of "day" or "hour" will return the usage for the specified period - segmented into daily or hourly aggregates. A window_size of "none" will return a - single usage aggregate for the entirety of the specified period. - - next_page: Cursor that indicates where the next page of results should start. - - billable_metrics: A list of billable metrics to fetch usage for. If absent, all billable metrics - will be returned. - - customer_ids: A list of Metronome customer IDs to fetch usage for. If absent, usage for all - customers will be returned. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/usage", - page=SyncCursorPageWithoutLimit[UsageListResponse], - body=maybe_transform( - { - "ending_before": ending_before, - "starting_on": starting_on, - "window_size": window_size, - "billable_metrics": billable_metrics, - "customer_ids": customer_ids, - }, - usage_list_params.UsageListParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"next_page": next_page}, usage_list_params.UsageListParams), - ), - model=UsageListResponse, - method="post", - ) - - def ingest( - self, - *, - usage: Iterable[usage_ingest_params.Usage] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - The ingest endpoint is the primary method for sending usage events to Metronome, - serving as the foundation for all billing calculations in your usage-based - pricing model. This high-throughput endpoint is designed for real-time streaming - ingestion, supports backdating 34 days, and is built to handle mission-critical - usage data with enterprise-grade reliability. Metronome supports 100,000 events - per second without requiring pre-aggregation or rollups and can scale up from - there. See the [Send usage events](/guides/events/send-usage-events) guide to - learn more about usage events. - - ### Use this endpoint to: - - Create a customer usage pipeline into Metronome that drives billable metrics, - credit drawdown, and invoicing. Track customer behavior, resource consumption, - and feature usage - - ### What happens when you send events: - - - Events are validated and processed in real-time - - Events are matched to customers using customer IDs or customer ingest aliases - - Events are matched to billable metrics and are immediately available for usage - and spend calculations - - ### Usage guidelines: - - - Historical events can be backdated up to 34 days and will immediately impact - live customer spend - - Duplicate events are automatically detected and ignored (34-day deduplication - window) - - #### Event structure: - - Usage events are simple JSON objects designed for flexibility and ease of - integration: - - ```json - { - "transaction_id": "2021-01-01T00:00:00Z_cluster42", - "customer_id": "team@example.com", - "event_type": "api_request", - "timestamp": "2021-01-01T00:00:00Z", - "properties": { - "endpoint": "/v1/users", - "method": "POST", - "response_time_ms": 45, - "region": "us-west-2" - } - } - ``` - - Learn more about - [usage event structure definitions](/guides/events/design-usage-events). - - #### Transaction ID - - The transaction_id serves as your idempotency key, ensuring events are processed - exactly once. Metronome maintains a 34-day deduplication window - significantly - longer than typical 12-hour windows - enabling robust backfill scenarios without - duplicate billing. - - - Best Practices: - - Use UUIDs for one-time events: uuid4() - - For heartbeat events, use deterministic IDs - - Include enough context to avoid collisions across different event sources - - #### Customer ID - - Identifies which customer should be billed for this usage. Supports two - identification methods: - - - Metronome Customer ID: The UUID returned when creating a customer - - Ingest Alias: Your system's identifier (email, account number, etc.) - - Ingest aliases enable seamless integration without requiring ID mapping, and - customers can have multiple aliases for flexibility. - - #### Event Type: - - Categorizes the event type for billable metric matching. Choose descriptive - names that aligns with the product surface area. - - #### Properties: - - Flexible metadata also used to match billable metrics or to be used to serve as - group keys to create multiple pricing dimensions or breakdown costs by novel - properties for end customers or internal finance teams measuring underlying - COGs. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return self._post( - "/v1/ingest", - body=maybe_transform(usage, Iterable[usage_ingest_params.Usage]), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def list_with_groups( - self, - *, - billable_metric_id: str, - customer_id: str, - window_size: Literal["HOUR", "DAY", "NONE"], - limit: int | Omit = omit, - next_page: str | Omit = omit, - current_period: bool | Omit = omit, - ending_before: Union[str, datetime] | Omit = omit, - group_by: usage_list_with_groups_params.GroupBy | Omit = omit, - group_filters: Dict[str, SequenceNotStr[str]] | Omit = omit, - group_key: SequenceNotStr[str] | Omit = omit, - starting_on: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> SyncCursorPage[UsageListWithGroupsResponse]: - """ - Retrieve granular usage data for a specific customer and billable metric, with - the ability to break down usage by custom grouping dimensions. This endpoint - enables deep usage analytics by segmenting data across attributes like region, - user, model type, or any custom dimension defined in your billable metrics. - - ### Use this endpoint to: - - - Analyze usage patterns broken down by specific attributes (region, user, - department, etc.) - - Build detailed usage dashboards with dimensional filtering - - Identify high-usage segments for optimization opportunities - - ### Request parameters - - Use [`group_key`](#body-group-key) and [`group_filters`](#body-group-filters) to - group by one or more dimensions. This is required for compound group keys and - recommended for all new integrations: - - ```json - { - "group_key": ["region", "team"], - "group_filters": { - "region": ["US-East", "US-West"] - } - } - ``` - - Important: For compound group keys, you must pass the complete set of keys that - make up the compound key. Partial key combinations are not supported. For - example, if your billable metric has a compound group key [region, team, - environment], you must pass all three keys in group_key—you cannot pass just - `[region]` or `[region, team]`. - - ### Key response fields: - - An array of `PagedUsageAggregate` objects containing: - - - `starting_on` and `ending_before`: Time window boundaries - - `group`: Object mapping group keys to their values - - For simple groups, this will be a map with a single key-value pair (e.g., - `{"region": "US-East"}`) - - For compound groups, this will be a map with multiple key-value pairs (e.g., - `{"region": "US-East", "team": "engineering"}`) - - `value`: Aggregated usage for this group and time window - - `next_page`: Pagination cursor for large datasets - - ### Usage guidelines: - - - Required parameters: Must specify `customer_id`, `billable_metric_id`, and - `window_size` - - Time windows: Set `window_size` to hour, day, or none for different - granularities - - Group filtering: Use `group_key` and `group_filters` to specify groups and - group filters - - Limits: When using compound group keys (2+ keys in `group_key`), the default - and max limit is 100 - - Pagination: Use limit and `next_page` for large result sets - - Null handling: Group values may be null for events missing the group key - property - - Args: - window_size: A window_size of "day" or "hour" will return the usage for the specified period - segmented into daily or hourly aggregates. A window_size of "none" will return a - single usage aggregate for the entirety of the specified period. - - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - current_period: If true, will return the usage for the current billing period. Will return an - error if the customer is currently uncontracted or starting_on and ending_before - are specified when this is true. - - group_by: Use group_key and group_filters instead. Use a single group key to group by. - Compound group keys are not supported. - - group_filters: Object mapping group keys to arrays of values to filter on. Only usage matching - these filter values will be returned. Keys must be present in group_key. Omit a - key or use an empty array to include all values for that dimension. - - group_key: Group key to group usage by. Supports both simple (single key) and compound - (multiple keys) group keys. - - For simple group keys, provide a single key e.g. `["region"]`. For compound - group keys, provide multiple keys e.g. `["region", "team"]`. - - For streaming metrics, the keys must be defined as a simple or compound group - key on the billable metric. For compound group keys, all keys must match an - exact compound group key definition — partial matches are not allowed. - - Cannot be used together with `group_by`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/usage/groups", - page=SyncCursorPage[UsageListWithGroupsResponse], - body=maybe_transform( - { - "billable_metric_id": billable_metric_id, - "customer_id": customer_id, - "window_size": window_size, - "current_period": current_period, - "ending_before": ending_before, - "group_by": group_by, - "group_filters": group_filters, - "group_key": group_key, - "starting_on": starting_on, - }, - usage_list_with_groups_params.UsageListWithGroupsParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - usage_list_with_groups_params.UsageListWithGroupsParams, - ), - ), - model=UsageListWithGroupsResponse, - method="post", - ) - - def search( - self, - *, - transaction_ids: SequenceNotStr[str], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> UsageSearchResponse: - """ - This endpoint retrieves events by transaction ID for events that occurred within - the last 34 days. It is specifically designed for sampling-based testing - workflows to detect revenue leakage. The Event Search API provides a critical - observability tool that validates the integrity of your usage pipeline by - allowing you to sample raw events and verify their matching against active - billable metrics. - - Why event observability matters for revenue leakage: Silent revenue loss occurs - when events are dropped, delayed, or fail to match billable metrics due to: - - - Upstream system failures - - Event format changes - - Misconfigured billable metrics - - ### Use this endpoint to: - - - Sample raw events and validate they match the expected billable metrics - - Build custom leakage detection alerts to prevent silent revenue loss - - Verify event processing accuracy during system changes or metric updates - - Debug event matching issues in real-time - - ### Key response fields: - - - Complete event details including transaction ID, customer ID, and properties - - Matched Metronome customer (if any) - - Matched billable metric information (if any) - - Processing status and duplicate detection flags - - ### Usage guidelines: - - ⚠️ Important: This endpoint is heavily rate limited and designed for sampling - workflows only. Do not use this endpoint to check every event in your system. - Instead, implement a sampling strategy to randomly validate a subset of events - for observability purposes. - - Args: - transaction_ids: The transaction IDs of the events to retrieve - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v1/events/search", - body=maybe_transform({"transaction_ids": transaction_ids}, usage_search_params.UsageSearchParams), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=UsageSearchResponse, - ) - - -class AsyncUsageResource(AsyncAPIResource): - """ - [Usage events](https://docs.metronome.com/connecting-metronome/send-usage-data/) are the basis for billable metrics. Use these endpoints to send usage events to Metronome and retrieve aggregated event data. - """ - - @cached_property - def with_raw_response(self) -> AsyncUsageResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncUsageResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncUsageResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncUsageResourceWithStreamingResponse(self) - - def list( - self, - *, - ending_before: Union[str, datetime], - starting_on: Union[str, datetime], - window_size: Literal["HOUR", "DAY", "NONE"], - next_page: str | Omit = omit, - billable_metrics: Iterable[usage_list_params.BillableMetric] | Omit = omit, - customer_ids: SequenceNotStr[str] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[UsageListResponse, AsyncCursorPageWithoutLimit[UsageListResponse]]: - """ - Retrieve aggregated usage data across multiple customers and billable metrics in - a single query. This batch endpoint enables you to fetch usage patterns at - scale, broken down by time windows, making it ideal for building analytics - dashboards, generating reports, and monitoring platform-wide usage trends. - - ### Use this endpoint to: - - - Generate platform-wide usage reports for internal teams - - Monitor aggregate usage trends across your entire customer base - - Create comparative usage analyses between customers or time periods - - Support capacity planning with historical usage patterns - - ### Key response fields: - - An array of `UsageBatchAggregate` objects containing: - - - `customer_id`: The customer this usage belongs to - - `billable_metric_id` and `billable_metric_name`: What was measured - - `start_timestamp` and `end_timestamp`: Time window for this data point - - `value`: Aggregated usage amount for the period - - `groups` (optional): Usage broken down by group keys with values - - `next_page`: Pagination cursor for large result sets - - ### Usage guidelines: - - - Time windows: Set `window_size` to `hour`, `day`, or `none` (entire period) - - Required parameters: Must specify `starting_on`, `ending_before`, and - `window_size` - - Filtering options: - - `customer_ids`: Limit to specific customers (omit for all customers) - - `billable_metrics`: Limit to specific metrics (omit for all metrics) - - Pagination: Use `next_page` cursor to retrieve large datasets - - Null values: Group values may be null when no usage matches that group - - Args: - window_size: A window_size of "day" or "hour" will return the usage for the specified period - segmented into daily or hourly aggregates. A window_size of "none" will return a - single usage aggregate for the entirety of the specified period. - - next_page: Cursor that indicates where the next page of results should start. - - billable_metrics: A list of billable metrics to fetch usage for. If absent, all billable metrics - will be returned. - - customer_ids: A list of Metronome customer IDs to fetch usage for. If absent, usage for all - customers will be returned. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/usage", - page=AsyncCursorPageWithoutLimit[UsageListResponse], - body=maybe_transform( - { - "ending_before": ending_before, - "starting_on": starting_on, - "window_size": window_size, - "billable_metrics": billable_metrics, - "customer_ids": customer_ids, - }, - usage_list_params.UsageListParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform({"next_page": next_page}, usage_list_params.UsageListParams), - ), - model=UsageListResponse, - method="post", - ) - - async def ingest( - self, - *, - usage: Iterable[usage_ingest_params.Usage] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> None: - """ - The ingest endpoint is the primary method for sending usage events to Metronome, - serving as the foundation for all billing calculations in your usage-based - pricing model. This high-throughput endpoint is designed for real-time streaming - ingestion, supports backdating 34 days, and is built to handle mission-critical - usage data with enterprise-grade reliability. Metronome supports 100,000 events - per second without requiring pre-aggregation or rollups and can scale up from - there. See the [Send usage events](/guides/events/send-usage-events) guide to - learn more about usage events. - - ### Use this endpoint to: - - Create a customer usage pipeline into Metronome that drives billable metrics, - credit drawdown, and invoicing. Track customer behavior, resource consumption, - and feature usage - - ### What happens when you send events: - - - Events are validated and processed in real-time - - Events are matched to customers using customer IDs or customer ingest aliases - - Events are matched to billable metrics and are immediately available for usage - and spend calculations - - ### Usage guidelines: - - - Historical events can be backdated up to 34 days and will immediately impact - live customer spend - - Duplicate events are automatically detected and ignored (34-day deduplication - window) - - #### Event structure: - - Usage events are simple JSON objects designed for flexibility and ease of - integration: - - ```json - { - "transaction_id": "2021-01-01T00:00:00Z_cluster42", - "customer_id": "team@example.com", - "event_type": "api_request", - "timestamp": "2021-01-01T00:00:00Z", - "properties": { - "endpoint": "/v1/users", - "method": "POST", - "response_time_ms": 45, - "region": "us-west-2" - } - } - ``` - - Learn more about - [usage event structure definitions](/guides/events/design-usage-events). - - #### Transaction ID - - The transaction_id serves as your idempotency key, ensuring events are processed - exactly once. Metronome maintains a 34-day deduplication window - significantly - longer than typical 12-hour windows - enabling robust backfill scenarios without - duplicate billing. - - - Best Practices: - - Use UUIDs for one-time events: uuid4() - - For heartbeat events, use deterministic IDs - - Include enough context to avoid collisions across different event sources - - #### Customer ID - - Identifies which customer should be billed for this usage. Supports two - identification methods: - - - Metronome Customer ID: The UUID returned when creating a customer - - Ingest Alias: Your system's identifier (email, account number, etc.) - - Ingest aliases enable seamless integration without requiring ID mapping, and - customers can have multiple aliases for flexibility. - - #### Event Type: - - Categorizes the event type for billable metric matching. Choose descriptive - names that aligns with the product surface area. - - #### Properties: - - Flexible metadata also used to match billable metrics or to be used to serve as - group keys to create multiple pricing dimensions or breakdown costs by novel - properties for end customers or internal finance teams measuring underlying - COGs. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - extra_headers = {"Accept": "*/*", **(extra_headers or {})} - return await self._post( - "/v1/ingest", - body=await async_maybe_transform(usage, Iterable[usage_ingest_params.Usage]), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=NoneType, - ) - - def list_with_groups( - self, - *, - billable_metric_id: str, - customer_id: str, - window_size: Literal["HOUR", "DAY", "NONE"], - limit: int | Omit = omit, - next_page: str | Omit = omit, - current_period: bool | Omit = omit, - ending_before: Union[str, datetime] | Omit = omit, - group_by: usage_list_with_groups_params.GroupBy | Omit = omit, - group_filters: Dict[str, SequenceNotStr[str]] | Omit = omit, - group_key: SequenceNotStr[str] | Omit = omit, - starting_on: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> AsyncPaginator[UsageListWithGroupsResponse, AsyncCursorPage[UsageListWithGroupsResponse]]: - """ - Retrieve granular usage data for a specific customer and billable metric, with - the ability to break down usage by custom grouping dimensions. This endpoint - enables deep usage analytics by segmenting data across attributes like region, - user, model type, or any custom dimension defined in your billable metrics. - - ### Use this endpoint to: - - - Analyze usage patterns broken down by specific attributes (region, user, - department, etc.) - - Build detailed usage dashboards with dimensional filtering - - Identify high-usage segments for optimization opportunities - - ### Request parameters - - Use [`group_key`](#body-group-key) and [`group_filters`](#body-group-filters) to - group by one or more dimensions. This is required for compound group keys and - recommended for all new integrations: - - ```json - { - "group_key": ["region", "team"], - "group_filters": { - "region": ["US-East", "US-West"] - } - } - ``` - - Important: For compound group keys, you must pass the complete set of keys that - make up the compound key. Partial key combinations are not supported. For - example, if your billable metric has a compound group key [region, team, - environment], you must pass all three keys in group_key—you cannot pass just - `[region]` or `[region, team]`. - - ### Key response fields: - - An array of `PagedUsageAggregate` objects containing: - - - `starting_on` and `ending_before`: Time window boundaries - - `group`: Object mapping group keys to their values - - For simple groups, this will be a map with a single key-value pair (e.g., - `{"region": "US-East"}`) - - For compound groups, this will be a map with multiple key-value pairs (e.g., - `{"region": "US-East", "team": "engineering"}`) - - `value`: Aggregated usage for this group and time window - - `next_page`: Pagination cursor for large datasets - - ### Usage guidelines: - - - Required parameters: Must specify `customer_id`, `billable_metric_id`, and - `window_size` - - Time windows: Set `window_size` to hour, day, or none for different - granularities - - Group filtering: Use `group_key` and `group_filters` to specify groups and - group filters - - Limits: When using compound group keys (2+ keys in `group_key`), the default - and max limit is 100 - - Pagination: Use limit and `next_page` for large result sets - - Null handling: Group values may be null for events missing the group key - property - - Args: - window_size: A window_size of "day" or "hour" will return the usage for the specified period - segmented into daily or hourly aggregates. A window_size of "none" will return a - single usage aggregate for the entirety of the specified period. - - limit: Max number of results that should be returned - - next_page: Cursor that indicates where the next page of results should start. - - current_period: If true, will return the usage for the current billing period. Will return an - error if the customer is currently uncontracted or starting_on and ending_before - are specified when this is true. - - group_by: Use group_key and group_filters instead. Use a single group key to group by. - Compound group keys are not supported. - - group_filters: Object mapping group keys to arrays of values to filter on. Only usage matching - these filter values will be returned. Keys must be present in group_key. Omit a - key or use an empty array to include all values for that dimension. - - group_key: Group key to group usage by. Supports both simple (single key) and compound - (multiple keys) group keys. - - For simple group keys, provide a single key e.g. `["region"]`. For compound - group keys, provide multiple keys e.g. `["region", "team"]`. - - For streaming metrics, the keys must be defined as a simple or compound group - key on the billable metric. For compound group keys, all keys must match an - exact compound group key definition — partial matches are not allowed. - - Cannot be used together with `group_by`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._get_api_list( - "/v1/usage/groups", - page=AsyncCursorPage[UsageListWithGroupsResponse], - body=maybe_transform( - { - "billable_metric_id": billable_metric_id, - "customer_id": customer_id, - "window_size": window_size, - "current_period": current_period, - "ending_before": ending_before, - "group_by": group_by, - "group_filters": group_filters, - "group_key": group_key, - "starting_on": starting_on, - }, - usage_list_with_groups_params.UsageListWithGroupsParams, - ), - options=make_request_options( - extra_headers=extra_headers, - extra_query=extra_query, - extra_body=extra_body, - timeout=timeout, - query=maybe_transform( - { - "limit": limit, - "next_page": next_page, - }, - usage_list_with_groups_params.UsageListWithGroupsParams, - ), - ), - model=UsageListWithGroupsResponse, - method="post", - ) - - async def search( - self, - *, - transaction_ids: SequenceNotStr[str], - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> UsageSearchResponse: - """ - This endpoint retrieves events by transaction ID for events that occurred within - the last 34 days. It is specifically designed for sampling-based testing - workflows to detect revenue leakage. The Event Search API provides a critical - observability tool that validates the integrity of your usage pipeline by - allowing you to sample raw events and verify their matching against active - billable metrics. - - Why event observability matters for revenue leakage: Silent revenue loss occurs - when events are dropped, delayed, or fail to match billable metrics due to: - - - Upstream system failures - - Event format changes - - Misconfigured billable metrics - - ### Use this endpoint to: - - - Sample raw events and validate they match the expected billable metrics - - Build custom leakage detection alerts to prevent silent revenue loss - - Verify event processing accuracy during system changes or metric updates - - Debug event matching issues in real-time - - ### Key response fields: - - - Complete event details including transaction ID, customer ID, and properties - - Matched Metronome customer (if any) - - Matched billable metric information (if any) - - Processing status and duplicate detection flags - - ### Usage guidelines: - - ⚠️ Important: This endpoint is heavily rate limited and designed for sampling - workflows only. Do not use this endpoint to check every event in your system. - Instead, implement a sampling strategy to randomly validate a subset of events - for observability purposes. - - Args: - transaction_ids: The transaction IDs of the events to retrieve - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v1/events/search", - body=await async_maybe_transform( - {"transaction_ids": transaction_ids}, usage_search_params.UsageSearchParams - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=UsageSearchResponse, - ) - - -class UsageResourceWithRawResponse: - def __init__(self, usage: UsageResource) -> None: - self._usage = usage - - self.list = to_raw_response_wrapper( - usage.list, - ) - self.ingest = to_raw_response_wrapper( - usage.ingest, - ) - self.list_with_groups = to_raw_response_wrapper( - usage.list_with_groups, - ) - self.search = to_raw_response_wrapper( - usage.search, - ) - - -class AsyncUsageResourceWithRawResponse: - def __init__(self, usage: AsyncUsageResource) -> None: - self._usage = usage - - self.list = async_to_raw_response_wrapper( - usage.list, - ) - self.ingest = async_to_raw_response_wrapper( - usage.ingest, - ) - self.list_with_groups = async_to_raw_response_wrapper( - usage.list_with_groups, - ) - self.search = async_to_raw_response_wrapper( - usage.search, - ) - - -class UsageResourceWithStreamingResponse: - def __init__(self, usage: UsageResource) -> None: - self._usage = usage - - self.list = to_streamed_response_wrapper( - usage.list, - ) - self.ingest = to_streamed_response_wrapper( - usage.ingest, - ) - self.list_with_groups = to_streamed_response_wrapper( - usage.list_with_groups, - ) - self.search = to_streamed_response_wrapper( - usage.search, - ) - - -class AsyncUsageResourceWithStreamingResponse: - def __init__(self, usage: AsyncUsageResource) -> None: - self._usage = usage - - self.list = async_to_streamed_response_wrapper( - usage.list, - ) - self.ingest = async_to_streamed_response_wrapper( - usage.ingest, - ) - self.list_with_groups = async_to_streamed_response_wrapper( - usage.list_with_groups, - ) - self.search = async_to_streamed_response_wrapper( - usage.search, - ) diff --git a/src/metronome/resources/v1/v1.py b/src/metronome/resources/v1/v1.py deleted file mode 100644 index b8d60cfaf..000000000 --- a/src/metronome/resources/v1/v1.py +++ /dev/null @@ -1,798 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .plans import ( - PlansResource, - AsyncPlansResource, - PlansResourceWithRawResponse, - AsyncPlansResourceWithRawResponse, - PlansResourceWithStreamingResponse, - AsyncPlansResourceWithStreamingResponse, -) -from .usage import ( - UsageResource, - AsyncUsageResource, - UsageResourceWithRawResponse, - AsyncUsageResourceWithRawResponse, - UsageResourceWithStreamingResponse, - AsyncUsageResourceWithStreamingResponse, -) -from .alerts import ( - AlertsResource, - AsyncAlertsResource, - AlertsResourceWithRawResponse, - AsyncAlertsResourceWithRawResponse, - AlertsResourceWithStreamingResponse, - AsyncAlertsResourceWithStreamingResponse, -) -from .invoices import ( - InvoicesResource, - AsyncInvoicesResource, - InvoicesResourceWithRawResponse, - AsyncInvoicesResourceWithRawResponse, - InvoicesResourceWithStreamingResponse, - AsyncInvoicesResourceWithStreamingResponse, -) -from .packages import ( - PackagesResource, - AsyncPackagesResource, - PackagesResourceWithRawResponse, - AsyncPackagesResourceWithRawResponse, - PackagesResourceWithStreamingResponse, - AsyncPackagesResourceWithStreamingResponse, -) -from .payments import ( - PaymentsResource, - AsyncPaymentsResource, - PaymentsResourceWithRawResponse, - AsyncPaymentsResourceWithRawResponse, - PaymentsResourceWithStreamingResponse, - AsyncPaymentsResourceWithStreamingResponse, -) -from .services import ( - ServicesResource, - AsyncServicesResource, - ServicesResourceWithRawResponse, - AsyncServicesResourceWithRawResponse, - ServicesResourceWithStreamingResponse, - AsyncServicesResourceWithStreamingResponse, -) -from ..._compat import cached_property -from .audit_logs import ( - AuditLogsResource, - AsyncAuditLogsResource, - AuditLogsResourceWithRawResponse, - AsyncAuditLogsResourceWithRawResponse, - AuditLogsResourceWithStreamingResponse, - AsyncAuditLogsResourceWithStreamingResponse, -) -from .dashboards import ( - DashboardsResource, - AsyncDashboardsResource, - DashboardsResourceWithRawResponse, - AsyncDashboardsResourceWithRawResponse, - DashboardsResourceWithStreamingResponse, - AsyncDashboardsResourceWithStreamingResponse, -) -from ..._resource import SyncAPIResource, AsyncAPIResource -from .credit_grants import ( - CreditGrantsResource, - AsyncCreditGrantsResource, - CreditGrantsResourceWithRawResponse, - AsyncCreditGrantsResourceWithRawResponse, - CreditGrantsResourceWithStreamingResponse, - AsyncCreditGrantsResourceWithStreamingResponse, -) -from .custom_fields import ( - CustomFieldsResource, - AsyncCustomFieldsResource, - CustomFieldsResourceWithRawResponse, - AsyncCustomFieldsResourceWithRawResponse, - CustomFieldsResourceWithStreamingResponse, - AsyncCustomFieldsResourceWithStreamingResponse, -) -from .pricing_units import ( - PricingUnitsResource, - AsyncPricingUnitsResource, - PricingUnitsResourceWithRawResponse, - AsyncPricingUnitsResourceWithRawResponse, - PricingUnitsResourceWithStreamingResponse, - AsyncPricingUnitsResourceWithStreamingResponse, -) -from .billable_metrics import ( - BillableMetricsResource, - AsyncBillableMetricsResource, - BillableMetricsResourceWithRawResponse, - AsyncBillableMetricsResourceWithRawResponse, - BillableMetricsResourceWithStreamingResponse, - AsyncBillableMetricsResourceWithStreamingResponse, -) -from .settings.settings import ( - SettingsResource, - AsyncSettingsResource, - SettingsResourceWithRawResponse, - AsyncSettingsResourceWithRawResponse, - SettingsResourceWithStreamingResponse, - AsyncSettingsResourceWithStreamingResponse, -) -from .contracts.contracts import ( - ContractsResource, - AsyncContractsResource, - ContractsResourceWithRawResponse, - AsyncContractsResourceWithRawResponse, - ContractsResourceWithStreamingResponse, - AsyncContractsResourceWithStreamingResponse, -) -from .customers.customers import ( - CustomersResource, - AsyncCustomersResource, - CustomersResourceWithRawResponse, - AsyncCustomersResourceWithRawResponse, - CustomersResourceWithStreamingResponse, - AsyncCustomersResourceWithStreamingResponse, -) - -__all__ = ["V1Resource", "AsyncV1Resource"] - - -class V1Resource(SyncAPIResource): - @cached_property - def alerts(self) -> AlertsResource: - """ - [Alerts](https://docs.metronome.com/connecting-metronome/alerts/) monitor customer spending, balances, and other billing factors. Use these endpoints to create, retrieve, and archive customer alerts. To view sample alert payloads by alert type, navigate [here.](https://docs.metronome.com/manage-product-access/create-manage-alerts/#webhook-notifications) - """ - return AlertsResource(self._client) - - @cached_property - def plans(self) -> PlansResource: - """ - [Plans](https://docs.metronome.com/pricing-and-packaging/create-plans/) determine the base pricing for a customer. Use these endpoints to add a plan to a customer, end a customer plan, retrieve plans, and retrieve plan details. Create plans in the [Metronome app](https://app.metronome.com/plans). - """ - return PlansResource(self._client) - - @cached_property - def credit_grants(self) -> CreditGrantsResource: - """ - [Credit grants](https://docs.metronome.com/invoicing/how-billing-works/manage-credits/) adjust a customer balance for prepayments, reimbursements, promotions, and so on. Use these endpoints to create, retrieve, update, and delete credit grants. - """ - return CreditGrantsResource(self._client) - - @cached_property - def pricing_units(self) -> PricingUnitsResource: - """ - Use these endpoints to configure a billing API key, a webhook secret, or invoice finalization behavior. - """ - return PricingUnitsResource(self._client) - - @cached_property - def customers(self) -> CustomersResource: - return CustomersResource(self._client) - - @cached_property - def dashboards(self) -> DashboardsResource: - """ - [Customers](https://docs.metronome.com/provisioning/create-customers/) in Metronome represent your users for all billing and reporting. Use these endpoints to create, retrieve, update, and archive customers and their billing configuration. - """ - return DashboardsResource(self._client) - - @cached_property - def usage(self) -> UsageResource: - """ - [Usage events](https://docs.metronome.com/connecting-metronome/send-usage-data/) are the basis for billable metrics. Use these endpoints to send usage events to Metronome and retrieve aggregated event data. - """ - return UsageResource(self._client) - - @cached_property - def audit_logs(self) -> AuditLogsResource: - """ - [Security](https://docs.metronome.com/developer-resources/security/) endpoints allow you to retrieve security-related data. - """ - return AuditLogsResource(self._client) - - @cached_property - def custom_fields(self) -> CustomFieldsResource: - """ - [Custom fields](https://docs.metronome.com/integrations/custom-fields/) enable adding additional data to Metronome entities. Use these endpoints to create, retrieve, update, and delete custom fields. - """ - return CustomFieldsResource(self._client) - - @cached_property - def billable_metrics(self) -> BillableMetricsResource: - """ - [Billable metrics](https://docs.metronome.com/understanding-metronome/how-metronome-works#billable-metrics) in Metronome represent the various consumption components that Metronome meters and aggregates. - """ - return BillableMetricsResource(self._client) - - @cached_property - def services(self) -> ServicesResource: - """ - [Security](https://docs.metronome.com/developer-resources/security/) endpoints allow you to retrieve security-related data. - """ - return ServicesResource(self._client) - - @cached_property - def invoices(self) -> InvoicesResource: - """ - [Invoices](https://docs.metronome.com/invoicing/) reflect how much a customer spent during a period, which is the basis for billing. Metronome automatically generates invoices based upon your pricing, packaging, and usage events. Use these endpoints to retrieve invoices. - """ - return InvoicesResource(self._client) - - @cached_property - def contracts(self) -> ContractsResource: - return ContractsResource(self._client) - - @cached_property - def packages(self) -> PackagesResource: - return PackagesResource(self._client) - - @cached_property - def payments(self) -> PaymentsResource: - return PaymentsResource(self._client) - - @cached_property - def settings(self) -> SettingsResource: - """ - Use these endpoints to configure a billing API key, a webhook secret, or invoice finalization behavior. - """ - return SettingsResource(self._client) - - @cached_property - def with_raw_response(self) -> V1ResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return V1ResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> V1ResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return V1ResourceWithStreamingResponse(self) - - -class AsyncV1Resource(AsyncAPIResource): - @cached_property - def alerts(self) -> AsyncAlertsResource: - """ - [Alerts](https://docs.metronome.com/connecting-metronome/alerts/) monitor customer spending, balances, and other billing factors. Use these endpoints to create, retrieve, and archive customer alerts. To view sample alert payloads by alert type, navigate [here.](https://docs.metronome.com/manage-product-access/create-manage-alerts/#webhook-notifications) - """ - return AsyncAlertsResource(self._client) - - @cached_property - def plans(self) -> AsyncPlansResource: - """ - [Plans](https://docs.metronome.com/pricing-and-packaging/create-plans/) determine the base pricing for a customer. Use these endpoints to add a plan to a customer, end a customer plan, retrieve plans, and retrieve plan details. Create plans in the [Metronome app](https://app.metronome.com/plans). - """ - return AsyncPlansResource(self._client) - - @cached_property - def credit_grants(self) -> AsyncCreditGrantsResource: - """ - [Credit grants](https://docs.metronome.com/invoicing/how-billing-works/manage-credits/) adjust a customer balance for prepayments, reimbursements, promotions, and so on. Use these endpoints to create, retrieve, update, and delete credit grants. - """ - return AsyncCreditGrantsResource(self._client) - - @cached_property - def pricing_units(self) -> AsyncPricingUnitsResource: - """ - Use these endpoints to configure a billing API key, a webhook secret, or invoice finalization behavior. - """ - return AsyncPricingUnitsResource(self._client) - - @cached_property - def customers(self) -> AsyncCustomersResource: - return AsyncCustomersResource(self._client) - - @cached_property - def dashboards(self) -> AsyncDashboardsResource: - """ - [Customers](https://docs.metronome.com/provisioning/create-customers/) in Metronome represent your users for all billing and reporting. Use these endpoints to create, retrieve, update, and archive customers and their billing configuration. - """ - return AsyncDashboardsResource(self._client) - - @cached_property - def usage(self) -> AsyncUsageResource: - """ - [Usage events](https://docs.metronome.com/connecting-metronome/send-usage-data/) are the basis for billable metrics. Use these endpoints to send usage events to Metronome and retrieve aggregated event data. - """ - return AsyncUsageResource(self._client) - - @cached_property - def audit_logs(self) -> AsyncAuditLogsResource: - """ - [Security](https://docs.metronome.com/developer-resources/security/) endpoints allow you to retrieve security-related data. - """ - return AsyncAuditLogsResource(self._client) - - @cached_property - def custom_fields(self) -> AsyncCustomFieldsResource: - """ - [Custom fields](https://docs.metronome.com/integrations/custom-fields/) enable adding additional data to Metronome entities. Use these endpoints to create, retrieve, update, and delete custom fields. - """ - return AsyncCustomFieldsResource(self._client) - - @cached_property - def billable_metrics(self) -> AsyncBillableMetricsResource: - """ - [Billable metrics](https://docs.metronome.com/understanding-metronome/how-metronome-works#billable-metrics) in Metronome represent the various consumption components that Metronome meters and aggregates. - """ - return AsyncBillableMetricsResource(self._client) - - @cached_property - def services(self) -> AsyncServicesResource: - """ - [Security](https://docs.metronome.com/developer-resources/security/) endpoints allow you to retrieve security-related data. - """ - return AsyncServicesResource(self._client) - - @cached_property - def invoices(self) -> AsyncInvoicesResource: - """ - [Invoices](https://docs.metronome.com/invoicing/) reflect how much a customer spent during a period, which is the basis for billing. Metronome automatically generates invoices based upon your pricing, packaging, and usage events. Use these endpoints to retrieve invoices. - """ - return AsyncInvoicesResource(self._client) - - @cached_property - def contracts(self) -> AsyncContractsResource: - return AsyncContractsResource(self._client) - - @cached_property - def packages(self) -> AsyncPackagesResource: - return AsyncPackagesResource(self._client) - - @cached_property - def payments(self) -> AsyncPaymentsResource: - return AsyncPaymentsResource(self._client) - - @cached_property - def settings(self) -> AsyncSettingsResource: - """ - Use these endpoints to configure a billing API key, a webhook secret, or invoice finalization behavior. - """ - return AsyncSettingsResource(self._client) - - @cached_property - def with_raw_response(self) -> AsyncV1ResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncV1ResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncV1ResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncV1ResourceWithStreamingResponse(self) - - -class V1ResourceWithRawResponse: - def __init__(self, v1: V1Resource) -> None: - self._v1 = v1 - - @cached_property - def alerts(self) -> AlertsResourceWithRawResponse: - """ - [Alerts](https://docs.metronome.com/connecting-metronome/alerts/) monitor customer spending, balances, and other billing factors. Use these endpoints to create, retrieve, and archive customer alerts. To view sample alert payloads by alert type, navigate [here.](https://docs.metronome.com/manage-product-access/create-manage-alerts/#webhook-notifications) - """ - return AlertsResourceWithRawResponse(self._v1.alerts) - - @cached_property - def plans(self) -> PlansResourceWithRawResponse: - """ - [Plans](https://docs.metronome.com/pricing-and-packaging/create-plans/) determine the base pricing for a customer. Use these endpoints to add a plan to a customer, end a customer plan, retrieve plans, and retrieve plan details. Create plans in the [Metronome app](https://app.metronome.com/plans). - """ - return PlansResourceWithRawResponse(self._v1.plans) - - @cached_property - def credit_grants(self) -> CreditGrantsResourceWithRawResponse: - """ - [Credit grants](https://docs.metronome.com/invoicing/how-billing-works/manage-credits/) adjust a customer balance for prepayments, reimbursements, promotions, and so on. Use these endpoints to create, retrieve, update, and delete credit grants. - """ - return CreditGrantsResourceWithRawResponse(self._v1.credit_grants) - - @cached_property - def pricing_units(self) -> PricingUnitsResourceWithRawResponse: - """ - Use these endpoints to configure a billing API key, a webhook secret, or invoice finalization behavior. - """ - return PricingUnitsResourceWithRawResponse(self._v1.pricing_units) - - @cached_property - def customers(self) -> CustomersResourceWithRawResponse: - return CustomersResourceWithRawResponse(self._v1.customers) - - @cached_property - def dashboards(self) -> DashboardsResourceWithRawResponse: - """ - [Customers](https://docs.metronome.com/provisioning/create-customers/) in Metronome represent your users for all billing and reporting. Use these endpoints to create, retrieve, update, and archive customers and their billing configuration. - """ - return DashboardsResourceWithRawResponse(self._v1.dashboards) - - @cached_property - def usage(self) -> UsageResourceWithRawResponse: - """ - [Usage events](https://docs.metronome.com/connecting-metronome/send-usage-data/) are the basis for billable metrics. Use these endpoints to send usage events to Metronome and retrieve aggregated event data. - """ - return UsageResourceWithRawResponse(self._v1.usage) - - @cached_property - def audit_logs(self) -> AuditLogsResourceWithRawResponse: - """ - [Security](https://docs.metronome.com/developer-resources/security/) endpoints allow you to retrieve security-related data. - """ - return AuditLogsResourceWithRawResponse(self._v1.audit_logs) - - @cached_property - def custom_fields(self) -> CustomFieldsResourceWithRawResponse: - """ - [Custom fields](https://docs.metronome.com/integrations/custom-fields/) enable adding additional data to Metronome entities. Use these endpoints to create, retrieve, update, and delete custom fields. - """ - return CustomFieldsResourceWithRawResponse(self._v1.custom_fields) - - @cached_property - def billable_metrics(self) -> BillableMetricsResourceWithRawResponse: - """ - [Billable metrics](https://docs.metronome.com/understanding-metronome/how-metronome-works#billable-metrics) in Metronome represent the various consumption components that Metronome meters and aggregates. - """ - return BillableMetricsResourceWithRawResponse(self._v1.billable_metrics) - - @cached_property - def services(self) -> ServicesResourceWithRawResponse: - """ - [Security](https://docs.metronome.com/developer-resources/security/) endpoints allow you to retrieve security-related data. - """ - return ServicesResourceWithRawResponse(self._v1.services) - - @cached_property - def invoices(self) -> InvoicesResourceWithRawResponse: - """ - [Invoices](https://docs.metronome.com/invoicing/) reflect how much a customer spent during a period, which is the basis for billing. Metronome automatically generates invoices based upon your pricing, packaging, and usage events. Use these endpoints to retrieve invoices. - """ - return InvoicesResourceWithRawResponse(self._v1.invoices) - - @cached_property - def contracts(self) -> ContractsResourceWithRawResponse: - return ContractsResourceWithRawResponse(self._v1.contracts) - - @cached_property - def packages(self) -> PackagesResourceWithRawResponse: - return PackagesResourceWithRawResponse(self._v1.packages) - - @cached_property - def payments(self) -> PaymentsResourceWithRawResponse: - return PaymentsResourceWithRawResponse(self._v1.payments) - - @cached_property - def settings(self) -> SettingsResourceWithRawResponse: - """ - Use these endpoints to configure a billing API key, a webhook secret, or invoice finalization behavior. - """ - return SettingsResourceWithRawResponse(self._v1.settings) - - -class AsyncV1ResourceWithRawResponse: - def __init__(self, v1: AsyncV1Resource) -> None: - self._v1 = v1 - - @cached_property - def alerts(self) -> AsyncAlertsResourceWithRawResponse: - """ - [Alerts](https://docs.metronome.com/connecting-metronome/alerts/) monitor customer spending, balances, and other billing factors. Use these endpoints to create, retrieve, and archive customer alerts. To view sample alert payloads by alert type, navigate [here.](https://docs.metronome.com/manage-product-access/create-manage-alerts/#webhook-notifications) - """ - return AsyncAlertsResourceWithRawResponse(self._v1.alerts) - - @cached_property - def plans(self) -> AsyncPlansResourceWithRawResponse: - """ - [Plans](https://docs.metronome.com/pricing-and-packaging/create-plans/) determine the base pricing for a customer. Use these endpoints to add a plan to a customer, end a customer plan, retrieve plans, and retrieve plan details. Create plans in the [Metronome app](https://app.metronome.com/plans). - """ - return AsyncPlansResourceWithRawResponse(self._v1.plans) - - @cached_property - def credit_grants(self) -> AsyncCreditGrantsResourceWithRawResponse: - """ - [Credit grants](https://docs.metronome.com/invoicing/how-billing-works/manage-credits/) adjust a customer balance for prepayments, reimbursements, promotions, and so on. Use these endpoints to create, retrieve, update, and delete credit grants. - """ - return AsyncCreditGrantsResourceWithRawResponse(self._v1.credit_grants) - - @cached_property - def pricing_units(self) -> AsyncPricingUnitsResourceWithRawResponse: - """ - Use these endpoints to configure a billing API key, a webhook secret, or invoice finalization behavior. - """ - return AsyncPricingUnitsResourceWithRawResponse(self._v1.pricing_units) - - @cached_property - def customers(self) -> AsyncCustomersResourceWithRawResponse: - return AsyncCustomersResourceWithRawResponse(self._v1.customers) - - @cached_property - def dashboards(self) -> AsyncDashboardsResourceWithRawResponse: - """ - [Customers](https://docs.metronome.com/provisioning/create-customers/) in Metronome represent your users for all billing and reporting. Use these endpoints to create, retrieve, update, and archive customers and their billing configuration. - """ - return AsyncDashboardsResourceWithRawResponse(self._v1.dashboards) - - @cached_property - def usage(self) -> AsyncUsageResourceWithRawResponse: - """ - [Usage events](https://docs.metronome.com/connecting-metronome/send-usage-data/) are the basis for billable metrics. Use these endpoints to send usage events to Metronome and retrieve aggregated event data. - """ - return AsyncUsageResourceWithRawResponse(self._v1.usage) - - @cached_property - def audit_logs(self) -> AsyncAuditLogsResourceWithRawResponse: - """ - [Security](https://docs.metronome.com/developer-resources/security/) endpoints allow you to retrieve security-related data. - """ - return AsyncAuditLogsResourceWithRawResponse(self._v1.audit_logs) - - @cached_property - def custom_fields(self) -> AsyncCustomFieldsResourceWithRawResponse: - """ - [Custom fields](https://docs.metronome.com/integrations/custom-fields/) enable adding additional data to Metronome entities. Use these endpoints to create, retrieve, update, and delete custom fields. - """ - return AsyncCustomFieldsResourceWithRawResponse(self._v1.custom_fields) - - @cached_property - def billable_metrics(self) -> AsyncBillableMetricsResourceWithRawResponse: - """ - [Billable metrics](https://docs.metronome.com/understanding-metronome/how-metronome-works#billable-metrics) in Metronome represent the various consumption components that Metronome meters and aggregates. - """ - return AsyncBillableMetricsResourceWithRawResponse(self._v1.billable_metrics) - - @cached_property - def services(self) -> AsyncServicesResourceWithRawResponse: - """ - [Security](https://docs.metronome.com/developer-resources/security/) endpoints allow you to retrieve security-related data. - """ - return AsyncServicesResourceWithRawResponse(self._v1.services) - - @cached_property - def invoices(self) -> AsyncInvoicesResourceWithRawResponse: - """ - [Invoices](https://docs.metronome.com/invoicing/) reflect how much a customer spent during a period, which is the basis for billing. Metronome automatically generates invoices based upon your pricing, packaging, and usage events. Use these endpoints to retrieve invoices. - """ - return AsyncInvoicesResourceWithRawResponse(self._v1.invoices) - - @cached_property - def contracts(self) -> AsyncContractsResourceWithRawResponse: - return AsyncContractsResourceWithRawResponse(self._v1.contracts) - - @cached_property - def packages(self) -> AsyncPackagesResourceWithRawResponse: - return AsyncPackagesResourceWithRawResponse(self._v1.packages) - - @cached_property - def payments(self) -> AsyncPaymentsResourceWithRawResponse: - return AsyncPaymentsResourceWithRawResponse(self._v1.payments) - - @cached_property - def settings(self) -> AsyncSettingsResourceWithRawResponse: - """ - Use these endpoints to configure a billing API key, a webhook secret, or invoice finalization behavior. - """ - return AsyncSettingsResourceWithRawResponse(self._v1.settings) - - -class V1ResourceWithStreamingResponse: - def __init__(self, v1: V1Resource) -> None: - self._v1 = v1 - - @cached_property - def alerts(self) -> AlertsResourceWithStreamingResponse: - """ - [Alerts](https://docs.metronome.com/connecting-metronome/alerts/) monitor customer spending, balances, and other billing factors. Use these endpoints to create, retrieve, and archive customer alerts. To view sample alert payloads by alert type, navigate [here.](https://docs.metronome.com/manage-product-access/create-manage-alerts/#webhook-notifications) - """ - return AlertsResourceWithStreamingResponse(self._v1.alerts) - - @cached_property - def plans(self) -> PlansResourceWithStreamingResponse: - """ - [Plans](https://docs.metronome.com/pricing-and-packaging/create-plans/) determine the base pricing for a customer. Use these endpoints to add a plan to a customer, end a customer plan, retrieve plans, and retrieve plan details. Create plans in the [Metronome app](https://app.metronome.com/plans). - """ - return PlansResourceWithStreamingResponse(self._v1.plans) - - @cached_property - def credit_grants(self) -> CreditGrantsResourceWithStreamingResponse: - """ - [Credit grants](https://docs.metronome.com/invoicing/how-billing-works/manage-credits/) adjust a customer balance for prepayments, reimbursements, promotions, and so on. Use these endpoints to create, retrieve, update, and delete credit grants. - """ - return CreditGrantsResourceWithStreamingResponse(self._v1.credit_grants) - - @cached_property - def pricing_units(self) -> PricingUnitsResourceWithStreamingResponse: - """ - Use these endpoints to configure a billing API key, a webhook secret, or invoice finalization behavior. - """ - return PricingUnitsResourceWithStreamingResponse(self._v1.pricing_units) - - @cached_property - def customers(self) -> CustomersResourceWithStreamingResponse: - return CustomersResourceWithStreamingResponse(self._v1.customers) - - @cached_property - def dashboards(self) -> DashboardsResourceWithStreamingResponse: - """ - [Customers](https://docs.metronome.com/provisioning/create-customers/) in Metronome represent your users for all billing and reporting. Use these endpoints to create, retrieve, update, and archive customers and their billing configuration. - """ - return DashboardsResourceWithStreamingResponse(self._v1.dashboards) - - @cached_property - def usage(self) -> UsageResourceWithStreamingResponse: - """ - [Usage events](https://docs.metronome.com/connecting-metronome/send-usage-data/) are the basis for billable metrics. Use these endpoints to send usage events to Metronome and retrieve aggregated event data. - """ - return UsageResourceWithStreamingResponse(self._v1.usage) - - @cached_property - def audit_logs(self) -> AuditLogsResourceWithStreamingResponse: - """ - [Security](https://docs.metronome.com/developer-resources/security/) endpoints allow you to retrieve security-related data. - """ - return AuditLogsResourceWithStreamingResponse(self._v1.audit_logs) - - @cached_property - def custom_fields(self) -> CustomFieldsResourceWithStreamingResponse: - """ - [Custom fields](https://docs.metronome.com/integrations/custom-fields/) enable adding additional data to Metronome entities. Use these endpoints to create, retrieve, update, and delete custom fields. - """ - return CustomFieldsResourceWithStreamingResponse(self._v1.custom_fields) - - @cached_property - def billable_metrics(self) -> BillableMetricsResourceWithStreamingResponse: - """ - [Billable metrics](https://docs.metronome.com/understanding-metronome/how-metronome-works#billable-metrics) in Metronome represent the various consumption components that Metronome meters and aggregates. - """ - return BillableMetricsResourceWithStreamingResponse(self._v1.billable_metrics) - - @cached_property - def services(self) -> ServicesResourceWithStreamingResponse: - """ - [Security](https://docs.metronome.com/developer-resources/security/) endpoints allow you to retrieve security-related data. - """ - return ServicesResourceWithStreamingResponse(self._v1.services) - - @cached_property - def invoices(self) -> InvoicesResourceWithStreamingResponse: - """ - [Invoices](https://docs.metronome.com/invoicing/) reflect how much a customer spent during a period, which is the basis for billing. Metronome automatically generates invoices based upon your pricing, packaging, and usage events. Use these endpoints to retrieve invoices. - """ - return InvoicesResourceWithStreamingResponse(self._v1.invoices) - - @cached_property - def contracts(self) -> ContractsResourceWithStreamingResponse: - return ContractsResourceWithStreamingResponse(self._v1.contracts) - - @cached_property - def packages(self) -> PackagesResourceWithStreamingResponse: - return PackagesResourceWithStreamingResponse(self._v1.packages) - - @cached_property - def payments(self) -> PaymentsResourceWithStreamingResponse: - return PaymentsResourceWithStreamingResponse(self._v1.payments) - - @cached_property - def settings(self) -> SettingsResourceWithStreamingResponse: - """ - Use these endpoints to configure a billing API key, a webhook secret, or invoice finalization behavior. - """ - return SettingsResourceWithStreamingResponse(self._v1.settings) - - -class AsyncV1ResourceWithStreamingResponse: - def __init__(self, v1: AsyncV1Resource) -> None: - self._v1 = v1 - - @cached_property - def alerts(self) -> AsyncAlertsResourceWithStreamingResponse: - """ - [Alerts](https://docs.metronome.com/connecting-metronome/alerts/) monitor customer spending, balances, and other billing factors. Use these endpoints to create, retrieve, and archive customer alerts. To view sample alert payloads by alert type, navigate [here.](https://docs.metronome.com/manage-product-access/create-manage-alerts/#webhook-notifications) - """ - return AsyncAlertsResourceWithStreamingResponse(self._v1.alerts) - - @cached_property - def plans(self) -> AsyncPlansResourceWithStreamingResponse: - """ - [Plans](https://docs.metronome.com/pricing-and-packaging/create-plans/) determine the base pricing for a customer. Use these endpoints to add a plan to a customer, end a customer plan, retrieve plans, and retrieve plan details. Create plans in the [Metronome app](https://app.metronome.com/plans). - """ - return AsyncPlansResourceWithStreamingResponse(self._v1.plans) - - @cached_property - def credit_grants(self) -> AsyncCreditGrantsResourceWithStreamingResponse: - """ - [Credit grants](https://docs.metronome.com/invoicing/how-billing-works/manage-credits/) adjust a customer balance for prepayments, reimbursements, promotions, and so on. Use these endpoints to create, retrieve, update, and delete credit grants. - """ - return AsyncCreditGrantsResourceWithStreamingResponse(self._v1.credit_grants) - - @cached_property - def pricing_units(self) -> AsyncPricingUnitsResourceWithStreamingResponse: - """ - Use these endpoints to configure a billing API key, a webhook secret, or invoice finalization behavior. - """ - return AsyncPricingUnitsResourceWithStreamingResponse(self._v1.pricing_units) - - @cached_property - def customers(self) -> AsyncCustomersResourceWithStreamingResponse: - return AsyncCustomersResourceWithStreamingResponse(self._v1.customers) - - @cached_property - def dashboards(self) -> AsyncDashboardsResourceWithStreamingResponse: - """ - [Customers](https://docs.metronome.com/provisioning/create-customers/) in Metronome represent your users for all billing and reporting. Use these endpoints to create, retrieve, update, and archive customers and their billing configuration. - """ - return AsyncDashboardsResourceWithStreamingResponse(self._v1.dashboards) - - @cached_property - def usage(self) -> AsyncUsageResourceWithStreamingResponse: - """ - [Usage events](https://docs.metronome.com/connecting-metronome/send-usage-data/) are the basis for billable metrics. Use these endpoints to send usage events to Metronome and retrieve aggregated event data. - """ - return AsyncUsageResourceWithStreamingResponse(self._v1.usage) - - @cached_property - def audit_logs(self) -> AsyncAuditLogsResourceWithStreamingResponse: - """ - [Security](https://docs.metronome.com/developer-resources/security/) endpoints allow you to retrieve security-related data. - """ - return AsyncAuditLogsResourceWithStreamingResponse(self._v1.audit_logs) - - @cached_property - def custom_fields(self) -> AsyncCustomFieldsResourceWithStreamingResponse: - """ - [Custom fields](https://docs.metronome.com/integrations/custom-fields/) enable adding additional data to Metronome entities. Use these endpoints to create, retrieve, update, and delete custom fields. - """ - return AsyncCustomFieldsResourceWithStreamingResponse(self._v1.custom_fields) - - @cached_property - def billable_metrics(self) -> AsyncBillableMetricsResourceWithStreamingResponse: - """ - [Billable metrics](https://docs.metronome.com/understanding-metronome/how-metronome-works#billable-metrics) in Metronome represent the various consumption components that Metronome meters and aggregates. - """ - return AsyncBillableMetricsResourceWithStreamingResponse(self._v1.billable_metrics) - - @cached_property - def services(self) -> AsyncServicesResourceWithStreamingResponse: - """ - [Security](https://docs.metronome.com/developer-resources/security/) endpoints allow you to retrieve security-related data. - """ - return AsyncServicesResourceWithStreamingResponse(self._v1.services) - - @cached_property - def invoices(self) -> AsyncInvoicesResourceWithStreamingResponse: - """ - [Invoices](https://docs.metronome.com/invoicing/) reflect how much a customer spent during a period, which is the basis for billing. Metronome automatically generates invoices based upon your pricing, packaging, and usage events. Use these endpoints to retrieve invoices. - """ - return AsyncInvoicesResourceWithStreamingResponse(self._v1.invoices) - - @cached_property - def contracts(self) -> AsyncContractsResourceWithStreamingResponse: - return AsyncContractsResourceWithStreamingResponse(self._v1.contracts) - - @cached_property - def packages(self) -> AsyncPackagesResourceWithStreamingResponse: - return AsyncPackagesResourceWithStreamingResponse(self._v1.packages) - - @cached_property - def payments(self) -> AsyncPaymentsResourceWithStreamingResponse: - return AsyncPaymentsResourceWithStreamingResponse(self._v1.payments) - - @cached_property - def settings(self) -> AsyncSettingsResourceWithStreamingResponse: - """ - Use these endpoints to configure a billing API key, a webhook secret, or invoice finalization behavior. - """ - return AsyncSettingsResourceWithStreamingResponse(self._v1.settings) diff --git a/src/metronome/resources/v2/__init__.py b/src/metronome/resources/v2/__init__.py deleted file mode 100644 index b624d9b87..000000000 --- a/src/metronome/resources/v2/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .v2 import ( - V2Resource, - AsyncV2Resource, - V2ResourceWithRawResponse, - AsyncV2ResourceWithRawResponse, - V2ResourceWithStreamingResponse, - AsyncV2ResourceWithStreamingResponse, -) -from .contracts import ( - ContractsResource, - AsyncContractsResource, - ContractsResourceWithRawResponse, - AsyncContractsResourceWithRawResponse, - ContractsResourceWithStreamingResponse, - AsyncContractsResourceWithStreamingResponse, -) - -__all__ = [ - "ContractsResource", - "AsyncContractsResource", - "ContractsResourceWithRawResponse", - "AsyncContractsResourceWithRawResponse", - "ContractsResourceWithStreamingResponse", - "AsyncContractsResourceWithStreamingResponse", - "V2Resource", - "AsyncV2Resource", - "V2ResourceWithRawResponse", - "AsyncV2ResourceWithRawResponse", - "V2ResourceWithStreamingResponse", - "AsyncV2ResourceWithStreamingResponse", -] diff --git a/src/metronome/resources/v2/contracts.py b/src/metronome/resources/v2/contracts.py deleted file mode 100644 index 2c1630c08..000000000 --- a/src/metronome/resources/v2/contracts.py +++ /dev/null @@ -1,1361 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable, Optional -from datetime import datetime -from typing_extensions import Literal - -import httpx - -from ..._types import Body, Omit, Query, Headers, NotGiven, SequenceNotStr, omit, not_given -from ..._utils import maybe_transform, async_maybe_transform -from ..._compat import cached_property -from ...types.v2 import ( - contract_edit_params, - contract_list_params, - contract_retrieve_params, - contract_edit_commit_params, - contract_edit_credit_params, - contract_get_edit_history_params, -) -from ..._resource import SyncAPIResource, AsyncAPIResource -from ..._response import ( - to_raw_response_wrapper, - to_streamed_response_wrapper, - async_to_raw_response_wrapper, - async_to_streamed_response_wrapper, -) -from ..._base_client import make_request_options -from ...types.v2.contract_edit_response import ContractEditResponse -from ...types.v2.contract_list_response import ContractListResponse -from ...types.v2.contract_retrieve_response import ContractRetrieveResponse -from ...types.v2.contract_edit_commit_response import ContractEditCommitResponse -from ...types.v2.contract_edit_credit_response import ContractEditCreditResponse -from ...types.shared_params.commit_specifier_input import CommitSpecifierInput -from ...types.v2.contract_get_edit_history_response import ContractGetEditHistoryResponse -from ...types.shared_params.commit_hierarchy_configuration import CommitHierarchyConfiguration -from ...types.shared_params.spend_threshold_configuration_v2 import SpendThresholdConfigurationV2 -from ...types.shared_params.prepaid_balance_threshold_configuration_v2 import PrepaidBalanceThresholdConfigurationV2 - -__all__ = ["ContractsResource", "AsyncContractsResource"] - - -class ContractsResource(SyncAPIResource): - @cached_property - def with_raw_response(self) -> ContractsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return ContractsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> ContractsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return ContractsResourceWithStreamingResponse(self) - - def retrieve( - self, - *, - contract_id: str, - customer_id: str, - as_of_date: Union[str, datetime] | Omit = omit, - include_balance: bool | Omit = omit, - include_ledgers: bool | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractRetrieveResponse: - """ - Gets the details for a specific contract, including contract term, rate card - information, credits and commits, and more. - - ### Use this endpoint to: - - - Check the duration of a customer's current contract - - Get details on contract terms, including access schedule amounts for - commitments and credits - - Understand the state of a contract at a past time. As you can evolve the terms - of a contract over time through editing, use the `as_of_date` parameter to - view the full contract configuration as of that point in time. - - ### Usage guidelines: - - - Optionally, use the `include_balance` and `include_ledger` fields to include - balances and ledgers in the credit and commit responses. Using these fields - will cause the query to be slower. - - Args: - as_of_date: Optional RFC 3339 timestamp. Return the contract as of this date. Cannot be used - with include_ledgers parameter. - - include_balance: Include the balance of credits and commits in the response. Setting this flag - may cause the query to be slower. - - include_ledgers: Include commit/credit ledgers in the response. Setting this flag may cause the - query to be slower. Cannot be used with as_of_date parameter. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v2/contracts/get", - body=maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - "as_of_date": as_of_date, - "include_balance": include_balance, - "include_ledgers": include_ledgers, - }, - contract_retrieve_params.ContractRetrieveParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractRetrieveResponse, - ) - - def list( - self, - *, - customer_id: str, - covering_date: Union[str, datetime] | Omit = omit, - include_archived: bool | Omit = omit, - include_balance: bool | Omit = omit, - include_ledgers: bool | Omit = omit, - starting_at: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractListResponse: - """ - For a given customer, lists all of their contracts in chronological order. - - ### Use this endpoint to: - - - Check if a customer is provisioned with any contract, and at which tier - - Check the duration and terms of a customer's current contract - - Power a page in your end customer experience that shows the customer's history - of tiers (e.g. this customer started out on the Pro Plan, then downgraded to - the Starter plan). - - ### Usage guidelines: - - Use the `starting_at`, `covering_date`, and `include_archived` parameters to - filter the list of returned contracts. For example, to list only currently - active contracts, pass `covering_date` equal to the current time. - - Args: - covering_date: Optional RFC 3339 timestamp. Only include contracts active on the provided date. - This cannot be provided if starting_at filter is provided. - - include_archived: Include archived contracts in the response. - - include_balance: Include the balance of credits and commits in the response. Setting this flag - may cause the response to be slower. - - include_ledgers: Include commit/credit ledgers in the response. Setting this flag may cause the - response to be slower. - - starting_at: Optional RFC 3339 timestamp. Only include contracts that started on or after - this date. This cannot be provided if covering_date filter is provided. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v2/contracts/list", - body=maybe_transform( - { - "customer_id": customer_id, - "covering_date": covering_date, - "include_archived": include_archived, - "include_balance": include_balance, - "include_ledgers": include_ledgers, - "starting_at": starting_at, - }, - contract_list_params.ContractListParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractListResponse, - ) - - def edit( - self, - *, - contract_id: str, - customer_id: str, - add_billing_provider_configuration_update: contract_edit_params.AddBillingProviderConfigurationUpdate - | Omit = omit, - add_commits: Iterable[contract_edit_params.AddCommit] | Omit = omit, - add_credits: Iterable[contract_edit_params.AddCredit] | Omit = omit, - add_discounts: Iterable[contract_edit_params.AddDiscount] | Omit = omit, - add_overrides: Iterable[contract_edit_params.AddOverride] | Omit = omit, - add_prepaid_balance_threshold_configuration: PrepaidBalanceThresholdConfigurationV2 | Omit = omit, - add_professional_services: Iterable[contract_edit_params.AddProfessionalService] | Omit = omit, - add_recurring_commits: Iterable[contract_edit_params.AddRecurringCommit] | Omit = omit, - add_recurring_credits: Iterable[contract_edit_params.AddRecurringCredit] | Omit = omit, - add_reseller_royalties: Iterable[contract_edit_params.AddResellerRoyalty] | Omit = omit, - add_revenue_system_configuration_update: contract_edit_params.AddRevenueSystemConfigurationUpdate | Omit = omit, - add_scheduled_charges: Iterable[contract_edit_params.AddScheduledCharge] | Omit = omit, - add_spend_threshold_configuration: SpendThresholdConfigurationV2 | Omit = omit, - add_subscriptions: Iterable[contract_edit_params.AddSubscription] | Omit = omit, - allow_contract_ending_before_finalized_invoice: bool | Omit = omit, - archive_commits: Iterable[contract_edit_params.ArchiveCommit] | Omit = omit, - archive_credits: Iterable[contract_edit_params.ArchiveCredit] | Omit = omit, - archive_scheduled_charges: Iterable[contract_edit_params.ArchiveScheduledCharge] | Omit = omit, - remove_overrides: Iterable[contract_edit_params.RemoveOverride] | Omit = omit, - uniqueness_key: str | Omit = omit, - update_commits: Iterable[contract_edit_params.UpdateCommit] | Omit = omit, - update_contract_end_date: Union[str, datetime, None] | Omit = omit, - update_contract_name: Optional[str] | Omit = omit, - update_credits: Iterable[contract_edit_params.UpdateCredit] | Omit = omit, - update_net_payment_terms_days: Optional[float] | Omit = omit, - update_prepaid_balance_threshold_configuration: contract_edit_params.UpdatePrepaidBalanceThresholdConfiguration - | Omit = omit, - update_recurring_commits: Iterable[contract_edit_params.UpdateRecurringCommit] | Omit = omit, - update_recurring_credits: Iterable[contract_edit_params.UpdateRecurringCredit] | Omit = omit, - update_scheduled_charges: Iterable[contract_edit_params.UpdateScheduledCharge] | Omit = omit, - update_spend_threshold_configuration: contract_edit_params.UpdateSpendThresholdConfiguration | Omit = omit, - update_subscriptions: Iterable[contract_edit_params.UpdateSubscription] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractEditResponse: - """ - The ability to edit a contract helps you react quickly to the needs of your - customers and your business. - - ### Use this endpoint to: - - - Encode mid-term commitment and discount changes - - Fix configuration mistakes and easily roll back packaging changes - - ### Key response fields: - - - The `id` of the edit - - Complete edit details. For example, if you edited the contract to add new - overrides and credits, you will receive the IDs of those overrides and credits - in the response. - - ### Usage guidelines: - - - When you edit a contract, any draft invoices update immediately to reflect - that edit. Finalized invoices remain unchanged - you must void and regenerate - them in the UI or API to reflect the edit. - - Contract editing must be enabled to use this endpoint. Reach out to your - Metronome representative to learn more. - - Args: - contract_id: ID of the contract being edited - - customer_id: ID of the customer whose contract is being edited - - add_billing_provider_configuration_update: Update the billing provider configuration on the contract. Currently only - supports adding a billing provider configuration to a contract that does not - already have one. - - add_professional_services: This field's availability is dependent on your client's configuration. - - add_revenue_system_configuration_update: Update the revenue system configuration on the contract. Currently only supports - adding a revenue system configuration to a contract that does not already have - one. - - add_subscriptions: Optional list of - [subscriptions](https://docs.metronome.com/manage-product-access/create-subscription/) - to add to the contract. - - allow_contract_ending_before_finalized_invoice: If true, allows setting the contract end date earlier than the end_timestamp of - existing finalized invoices. Finalized invoices will be unchanged; if you want - to incorporate the new end date, you can void and regenerate finalized usage - invoices. Defaults to true. - - archive_commits: IDs of commits to archive - - archive_credits: IDs of credits to archive - - archive_scheduled_charges: IDs of scheduled charges to archive - - remove_overrides: IDs of overrides to remove - - uniqueness_key: Optional uniqueness key to prevent duplicate contract edits. - - update_contract_end_date: RFC 3339 timestamp indicating when the contract will end (exclusive). - - update_contract_name: Value to update the contract name to. If not provided, the contract name will - remain unchanged. - - update_net_payment_terms_days: Number of days after issuance of invoice after which the invoice is due (e.g. - Net 30). - - update_recurring_commits: Edits to these recurring commits will only affect commits whose access schedules - has not started. Expired commits, and commits with an active access schedule - will remain unchanged. - - update_recurring_credits: Edits to these recurring credits will only affect credits whose access schedules - has not started. Expired credits, and credits with an active access schedule - will remain unchanged. - - update_subscriptions: Optional list of subscriptions to update. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v2/contracts/edit", - body=maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - "add_billing_provider_configuration_update": add_billing_provider_configuration_update, - "add_commits": add_commits, - "add_credits": add_credits, - "add_discounts": add_discounts, - "add_overrides": add_overrides, - "add_prepaid_balance_threshold_configuration": add_prepaid_balance_threshold_configuration, - "add_professional_services": add_professional_services, - "add_recurring_commits": add_recurring_commits, - "add_recurring_credits": add_recurring_credits, - "add_reseller_royalties": add_reseller_royalties, - "add_revenue_system_configuration_update": add_revenue_system_configuration_update, - "add_scheduled_charges": add_scheduled_charges, - "add_spend_threshold_configuration": add_spend_threshold_configuration, - "add_subscriptions": add_subscriptions, - "allow_contract_ending_before_finalized_invoice": allow_contract_ending_before_finalized_invoice, - "archive_commits": archive_commits, - "archive_credits": archive_credits, - "archive_scheduled_charges": archive_scheduled_charges, - "remove_overrides": remove_overrides, - "uniqueness_key": uniqueness_key, - "update_commits": update_commits, - "update_contract_end_date": update_contract_end_date, - "update_contract_name": update_contract_name, - "update_credits": update_credits, - "update_net_payment_terms_days": update_net_payment_terms_days, - "update_prepaid_balance_threshold_configuration": update_prepaid_balance_threshold_configuration, - "update_recurring_commits": update_recurring_commits, - "update_recurring_credits": update_recurring_credits, - "update_scheduled_charges": update_scheduled_charges, - "update_spend_threshold_configuration": update_spend_threshold_configuration, - "update_subscriptions": update_subscriptions, - }, - contract_edit_params.ContractEditParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractEditResponse, - ) - - def edit_commit( - self, - *, - commit_id: str, - customer_id: str, - access_schedule: contract_edit_commit_params.AccessSchedule | Omit = omit, - applicable_product_ids: Optional[SequenceNotStr[str]] | Omit = omit, - applicable_product_tags: Optional[SequenceNotStr[str]] | Omit = omit, - description: str | Omit = omit, - hierarchy_configuration: CommitHierarchyConfiguration | Omit = omit, - invoice_contract_id: str | Omit = omit, - invoice_schedule: contract_edit_commit_params.InvoiceSchedule | Omit = omit, - name: str | Omit = omit, - priority: Optional[float] | Omit = omit, - product_id: str | Omit = omit, - rate_type: Literal["LIST_RATE", "COMMIT_RATE"] | Omit = omit, - specifiers: Optional[Iterable[CommitSpecifierInput]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractEditCommitResponse: - """Edit specific details for a contract-level or customer-level commit. - - Use this - endpoint to modify individual commit access schedules, invoice schedules, - applicable products, invoicing contracts, or other fields. - - ### Usage guidelines: - - - As with all edits in Metronome, draft invoices will reflect the edit - immediately, while finalized invoices are untouched unless voided and - regenerated. - - If a commit's invoice schedule item is associated with a finalized invoice, - you cannot remove or update the invoice schedule item. - - If a commit's invoice schedule item is associated with a voided invoice, you - cannot remove the invoice schedule item. - - You cannot remove an commit access schedule segment that was applied to a - finalized invoice. You can void the invoice beforehand and then remove the - access schedule segment. - - Args: - commit_id: ID of the commit to edit - - customer_id: ID of the customer whose commit is being edited - - applicable_product_ids: Which products the commit applies to. If applicable_product_ids, - applicable_product_tags or specifiers are not provided, the commit applies to - all products. - - applicable_product_tags: Which tags the commit applies to. If applicable_product_ids, - applicable_product_tags or specifiers are not provided, the commit applies to - all products. - - description: Updated description for the commit - - hierarchy_configuration: Optional configuration for commit hierarchy access control - - invoice_contract_id: ID of contract to use for invoicing - - name: Updated name for the commit - - priority: If multiple commits are applicable, the one with the lower priority will apply - first. - - rate_type: If provided, updates the commit to use the specified rate type for current and - future invoices. Previously finalized invoices will need to be voided and - regenerated to reflect the rate type change. - - specifiers: List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - Instead, to target usage by product or product tag, pass those values in the - body of `specifiers`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v2/contracts/commits/edit", - body=maybe_transform( - { - "commit_id": commit_id, - "customer_id": customer_id, - "access_schedule": access_schedule, - "applicable_product_ids": applicable_product_ids, - "applicable_product_tags": applicable_product_tags, - "description": description, - "hierarchy_configuration": hierarchy_configuration, - "invoice_contract_id": invoice_contract_id, - "invoice_schedule": invoice_schedule, - "name": name, - "priority": priority, - "product_id": product_id, - "rate_type": rate_type, - "specifiers": specifiers, - }, - contract_edit_commit_params.ContractEditCommitParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractEditCommitResponse, - ) - - def edit_credit( - self, - *, - credit_id: str, - customer_id: str, - access_schedule: contract_edit_credit_params.AccessSchedule | Omit = omit, - applicable_product_ids: Optional[SequenceNotStr[str]] | Omit = omit, - applicable_product_tags: Optional[SequenceNotStr[str]] | Omit = omit, - description: str | Omit = omit, - hierarchy_configuration: CommitHierarchyConfiguration | Omit = omit, - name: str | Omit = omit, - priority: Optional[float] | Omit = omit, - product_id: str | Omit = omit, - rate_type: Literal["LIST_RATE", "COMMIT_RATE"] | Omit = omit, - specifiers: Optional[Iterable[CommitSpecifierInput]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractEditCreditResponse: - """ - Edit details for a contract-level or customer-level credit. - - ### Use this endpoint to: - - - Extend the duration or the amount of an existing free credit like a trial - - Modify individual credit access schedules, applicable products, priority, or - other fields. - - ### Usage guidelines: - - - As with all edits in Metronome, draft invoices will reflect the edit - immediately, while finalized invoices are untouched unless voided and - regenerated. - - You cannot remove an access schedule segment that was applied to a finalized - invoice. You can void the invoice beforehand and then remove the access - schedule segment. - - Args: - credit_id: ID of the credit to edit - - customer_id: ID of the customer whose credit is being edited - - applicable_product_ids: Which products the credit applies to. If both applicable_product_ids and - applicable_product_tags are not provided, the credit applies to all products. - - applicable_product_tags: Which tags the credit applies to. If both applicable_product_ids and - applicable_product_tags are not provided, the credit applies to all products. - - description: Updated description for the credit - - hierarchy_configuration: Optional configuration for credit hierarchy access control - - name: Updated name for the credit - - priority: If multiple commits are applicable, the one with the lower priority will apply - first. - - rate_type: If provided, updates the credit to use the specified rate type for current and - future invoices. Previously finalized invoices will need to be voided and - regenerated to reflect the rate type change. - - specifiers: List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - Instead, to target usage by product or product tag, pass those values in the - body of `specifiers`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v2/contracts/credits/edit", - body=maybe_transform( - { - "credit_id": credit_id, - "customer_id": customer_id, - "access_schedule": access_schedule, - "applicable_product_ids": applicable_product_ids, - "applicable_product_tags": applicable_product_tags, - "description": description, - "hierarchy_configuration": hierarchy_configuration, - "name": name, - "priority": priority, - "product_id": product_id, - "rate_type": rate_type, - "specifiers": specifiers, - }, - contract_edit_credit_params.ContractEditCreditParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractEditCreditResponse, - ) - - def get_edit_history( - self, - *, - contract_id: str, - customer_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractGetEditHistoryResponse: - """List all the edits made to a contract over time. - - In Metronome, you can edit a - contract at any point after it's created to fix mistakes or reflect changes in - terms. Metronome stores a full history of all edits that were ever made to a - contract, whether through the UI, `editContract` endpoint, or other endpoints - like `updateContractEndDate`. - - ### Use this endpoint to: - - - Understand what changes were made to a contract, when, and by who - - ### Key response fields: - - - An array of every edit ever made to the contract - - Details on each individual edit - for example showing that in one edit, a user - added two discounts and incremented a subscription quantity. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return self._post( - "/v2/contracts/getEditHistory", - body=maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - }, - contract_get_edit_history_params.ContractGetEditHistoryParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractGetEditHistoryResponse, - ) - - -class AsyncContractsResource(AsyncAPIResource): - @cached_property - def with_raw_response(self) -> AsyncContractsResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncContractsResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncContractsResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncContractsResourceWithStreamingResponse(self) - - async def retrieve( - self, - *, - contract_id: str, - customer_id: str, - as_of_date: Union[str, datetime] | Omit = omit, - include_balance: bool | Omit = omit, - include_ledgers: bool | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractRetrieveResponse: - """ - Gets the details for a specific contract, including contract term, rate card - information, credits and commits, and more. - - ### Use this endpoint to: - - - Check the duration of a customer's current contract - - Get details on contract terms, including access schedule amounts for - commitments and credits - - Understand the state of a contract at a past time. As you can evolve the terms - of a contract over time through editing, use the `as_of_date` parameter to - view the full contract configuration as of that point in time. - - ### Usage guidelines: - - - Optionally, use the `include_balance` and `include_ledger` fields to include - balances and ledgers in the credit and commit responses. Using these fields - will cause the query to be slower. - - Args: - as_of_date: Optional RFC 3339 timestamp. Return the contract as of this date. Cannot be used - with include_ledgers parameter. - - include_balance: Include the balance of credits and commits in the response. Setting this flag - may cause the query to be slower. - - include_ledgers: Include commit/credit ledgers in the response. Setting this flag may cause the - query to be slower. Cannot be used with as_of_date parameter. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v2/contracts/get", - body=await async_maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - "as_of_date": as_of_date, - "include_balance": include_balance, - "include_ledgers": include_ledgers, - }, - contract_retrieve_params.ContractRetrieveParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractRetrieveResponse, - ) - - async def list( - self, - *, - customer_id: str, - covering_date: Union[str, datetime] | Omit = omit, - include_archived: bool | Omit = omit, - include_balance: bool | Omit = omit, - include_ledgers: bool | Omit = omit, - starting_at: Union[str, datetime] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractListResponse: - """ - For a given customer, lists all of their contracts in chronological order. - - ### Use this endpoint to: - - - Check if a customer is provisioned with any contract, and at which tier - - Check the duration and terms of a customer's current contract - - Power a page in your end customer experience that shows the customer's history - of tiers (e.g. this customer started out on the Pro Plan, then downgraded to - the Starter plan). - - ### Usage guidelines: - - Use the `starting_at`, `covering_date`, and `include_archived` parameters to - filter the list of returned contracts. For example, to list only currently - active contracts, pass `covering_date` equal to the current time. - - Args: - covering_date: Optional RFC 3339 timestamp. Only include contracts active on the provided date. - This cannot be provided if starting_at filter is provided. - - include_archived: Include archived contracts in the response. - - include_balance: Include the balance of credits and commits in the response. Setting this flag - may cause the response to be slower. - - include_ledgers: Include commit/credit ledgers in the response. Setting this flag may cause the - response to be slower. - - starting_at: Optional RFC 3339 timestamp. Only include contracts that started on or after - this date. This cannot be provided if covering_date filter is provided. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v2/contracts/list", - body=await async_maybe_transform( - { - "customer_id": customer_id, - "covering_date": covering_date, - "include_archived": include_archived, - "include_balance": include_balance, - "include_ledgers": include_ledgers, - "starting_at": starting_at, - }, - contract_list_params.ContractListParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractListResponse, - ) - - async def edit( - self, - *, - contract_id: str, - customer_id: str, - add_billing_provider_configuration_update: contract_edit_params.AddBillingProviderConfigurationUpdate - | Omit = omit, - add_commits: Iterable[contract_edit_params.AddCommit] | Omit = omit, - add_credits: Iterable[contract_edit_params.AddCredit] | Omit = omit, - add_discounts: Iterable[contract_edit_params.AddDiscount] | Omit = omit, - add_overrides: Iterable[contract_edit_params.AddOverride] | Omit = omit, - add_prepaid_balance_threshold_configuration: PrepaidBalanceThresholdConfigurationV2 | Omit = omit, - add_professional_services: Iterable[contract_edit_params.AddProfessionalService] | Omit = omit, - add_recurring_commits: Iterable[contract_edit_params.AddRecurringCommit] | Omit = omit, - add_recurring_credits: Iterable[contract_edit_params.AddRecurringCredit] | Omit = omit, - add_reseller_royalties: Iterable[contract_edit_params.AddResellerRoyalty] | Omit = omit, - add_revenue_system_configuration_update: contract_edit_params.AddRevenueSystemConfigurationUpdate | Omit = omit, - add_scheduled_charges: Iterable[contract_edit_params.AddScheduledCharge] | Omit = omit, - add_spend_threshold_configuration: SpendThresholdConfigurationV2 | Omit = omit, - add_subscriptions: Iterable[contract_edit_params.AddSubscription] | Omit = omit, - allow_contract_ending_before_finalized_invoice: bool | Omit = omit, - archive_commits: Iterable[contract_edit_params.ArchiveCommit] | Omit = omit, - archive_credits: Iterable[contract_edit_params.ArchiveCredit] | Omit = omit, - archive_scheduled_charges: Iterable[contract_edit_params.ArchiveScheduledCharge] | Omit = omit, - remove_overrides: Iterable[contract_edit_params.RemoveOverride] | Omit = omit, - uniqueness_key: str | Omit = omit, - update_commits: Iterable[contract_edit_params.UpdateCommit] | Omit = omit, - update_contract_end_date: Union[str, datetime, None] | Omit = omit, - update_contract_name: Optional[str] | Omit = omit, - update_credits: Iterable[contract_edit_params.UpdateCredit] | Omit = omit, - update_net_payment_terms_days: Optional[float] | Omit = omit, - update_prepaid_balance_threshold_configuration: contract_edit_params.UpdatePrepaidBalanceThresholdConfiguration - | Omit = omit, - update_recurring_commits: Iterable[contract_edit_params.UpdateRecurringCommit] | Omit = omit, - update_recurring_credits: Iterable[contract_edit_params.UpdateRecurringCredit] | Omit = omit, - update_scheduled_charges: Iterable[contract_edit_params.UpdateScheduledCharge] | Omit = omit, - update_spend_threshold_configuration: contract_edit_params.UpdateSpendThresholdConfiguration | Omit = omit, - update_subscriptions: Iterable[contract_edit_params.UpdateSubscription] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractEditResponse: - """ - The ability to edit a contract helps you react quickly to the needs of your - customers and your business. - - ### Use this endpoint to: - - - Encode mid-term commitment and discount changes - - Fix configuration mistakes and easily roll back packaging changes - - ### Key response fields: - - - The `id` of the edit - - Complete edit details. For example, if you edited the contract to add new - overrides and credits, you will receive the IDs of those overrides and credits - in the response. - - ### Usage guidelines: - - - When you edit a contract, any draft invoices update immediately to reflect - that edit. Finalized invoices remain unchanged - you must void and regenerate - them in the UI or API to reflect the edit. - - Contract editing must be enabled to use this endpoint. Reach out to your - Metronome representative to learn more. - - Args: - contract_id: ID of the contract being edited - - customer_id: ID of the customer whose contract is being edited - - add_billing_provider_configuration_update: Update the billing provider configuration on the contract. Currently only - supports adding a billing provider configuration to a contract that does not - already have one. - - add_professional_services: This field's availability is dependent on your client's configuration. - - add_revenue_system_configuration_update: Update the revenue system configuration on the contract. Currently only supports - adding a revenue system configuration to a contract that does not already have - one. - - add_subscriptions: Optional list of - [subscriptions](https://docs.metronome.com/manage-product-access/create-subscription/) - to add to the contract. - - allow_contract_ending_before_finalized_invoice: If true, allows setting the contract end date earlier than the end_timestamp of - existing finalized invoices. Finalized invoices will be unchanged; if you want - to incorporate the new end date, you can void and regenerate finalized usage - invoices. Defaults to true. - - archive_commits: IDs of commits to archive - - archive_credits: IDs of credits to archive - - archive_scheduled_charges: IDs of scheduled charges to archive - - remove_overrides: IDs of overrides to remove - - uniqueness_key: Optional uniqueness key to prevent duplicate contract edits. - - update_contract_end_date: RFC 3339 timestamp indicating when the contract will end (exclusive). - - update_contract_name: Value to update the contract name to. If not provided, the contract name will - remain unchanged. - - update_net_payment_terms_days: Number of days after issuance of invoice after which the invoice is due (e.g. - Net 30). - - update_recurring_commits: Edits to these recurring commits will only affect commits whose access schedules - has not started. Expired commits, and commits with an active access schedule - will remain unchanged. - - update_recurring_credits: Edits to these recurring credits will only affect credits whose access schedules - has not started. Expired credits, and credits with an active access schedule - will remain unchanged. - - update_subscriptions: Optional list of subscriptions to update. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v2/contracts/edit", - body=await async_maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - "add_billing_provider_configuration_update": add_billing_provider_configuration_update, - "add_commits": add_commits, - "add_credits": add_credits, - "add_discounts": add_discounts, - "add_overrides": add_overrides, - "add_prepaid_balance_threshold_configuration": add_prepaid_balance_threshold_configuration, - "add_professional_services": add_professional_services, - "add_recurring_commits": add_recurring_commits, - "add_recurring_credits": add_recurring_credits, - "add_reseller_royalties": add_reseller_royalties, - "add_revenue_system_configuration_update": add_revenue_system_configuration_update, - "add_scheduled_charges": add_scheduled_charges, - "add_spend_threshold_configuration": add_spend_threshold_configuration, - "add_subscriptions": add_subscriptions, - "allow_contract_ending_before_finalized_invoice": allow_contract_ending_before_finalized_invoice, - "archive_commits": archive_commits, - "archive_credits": archive_credits, - "archive_scheduled_charges": archive_scheduled_charges, - "remove_overrides": remove_overrides, - "uniqueness_key": uniqueness_key, - "update_commits": update_commits, - "update_contract_end_date": update_contract_end_date, - "update_contract_name": update_contract_name, - "update_credits": update_credits, - "update_net_payment_terms_days": update_net_payment_terms_days, - "update_prepaid_balance_threshold_configuration": update_prepaid_balance_threshold_configuration, - "update_recurring_commits": update_recurring_commits, - "update_recurring_credits": update_recurring_credits, - "update_scheduled_charges": update_scheduled_charges, - "update_spend_threshold_configuration": update_spend_threshold_configuration, - "update_subscriptions": update_subscriptions, - }, - contract_edit_params.ContractEditParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractEditResponse, - ) - - async def edit_commit( - self, - *, - commit_id: str, - customer_id: str, - access_schedule: contract_edit_commit_params.AccessSchedule | Omit = omit, - applicable_product_ids: Optional[SequenceNotStr[str]] | Omit = omit, - applicable_product_tags: Optional[SequenceNotStr[str]] | Omit = omit, - description: str | Omit = omit, - hierarchy_configuration: CommitHierarchyConfiguration | Omit = omit, - invoice_contract_id: str | Omit = omit, - invoice_schedule: contract_edit_commit_params.InvoiceSchedule | Omit = omit, - name: str | Omit = omit, - priority: Optional[float] | Omit = omit, - product_id: str | Omit = omit, - rate_type: Literal["LIST_RATE", "COMMIT_RATE"] | Omit = omit, - specifiers: Optional[Iterable[CommitSpecifierInput]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractEditCommitResponse: - """Edit specific details for a contract-level or customer-level commit. - - Use this - endpoint to modify individual commit access schedules, invoice schedules, - applicable products, invoicing contracts, or other fields. - - ### Usage guidelines: - - - As with all edits in Metronome, draft invoices will reflect the edit - immediately, while finalized invoices are untouched unless voided and - regenerated. - - If a commit's invoice schedule item is associated with a finalized invoice, - you cannot remove or update the invoice schedule item. - - If a commit's invoice schedule item is associated with a voided invoice, you - cannot remove the invoice schedule item. - - You cannot remove an commit access schedule segment that was applied to a - finalized invoice. You can void the invoice beforehand and then remove the - access schedule segment. - - Args: - commit_id: ID of the commit to edit - - customer_id: ID of the customer whose commit is being edited - - applicable_product_ids: Which products the commit applies to. If applicable_product_ids, - applicable_product_tags or specifiers are not provided, the commit applies to - all products. - - applicable_product_tags: Which tags the commit applies to. If applicable_product_ids, - applicable_product_tags or specifiers are not provided, the commit applies to - all products. - - description: Updated description for the commit - - hierarchy_configuration: Optional configuration for commit hierarchy access control - - invoice_contract_id: ID of contract to use for invoicing - - name: Updated name for the commit - - priority: If multiple commits are applicable, the one with the lower priority will apply - first. - - rate_type: If provided, updates the commit to use the specified rate type for current and - future invoices. Previously finalized invoices will need to be voided and - regenerated to reflect the rate type change. - - specifiers: List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - Instead, to target usage by product or product tag, pass those values in the - body of `specifiers`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v2/contracts/commits/edit", - body=await async_maybe_transform( - { - "commit_id": commit_id, - "customer_id": customer_id, - "access_schedule": access_schedule, - "applicable_product_ids": applicable_product_ids, - "applicable_product_tags": applicable_product_tags, - "description": description, - "hierarchy_configuration": hierarchy_configuration, - "invoice_contract_id": invoice_contract_id, - "invoice_schedule": invoice_schedule, - "name": name, - "priority": priority, - "product_id": product_id, - "rate_type": rate_type, - "specifiers": specifiers, - }, - contract_edit_commit_params.ContractEditCommitParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractEditCommitResponse, - ) - - async def edit_credit( - self, - *, - credit_id: str, - customer_id: str, - access_schedule: contract_edit_credit_params.AccessSchedule | Omit = omit, - applicable_product_ids: Optional[SequenceNotStr[str]] | Omit = omit, - applicable_product_tags: Optional[SequenceNotStr[str]] | Omit = omit, - description: str | Omit = omit, - hierarchy_configuration: CommitHierarchyConfiguration | Omit = omit, - name: str | Omit = omit, - priority: Optional[float] | Omit = omit, - product_id: str | Omit = omit, - rate_type: Literal["LIST_RATE", "COMMIT_RATE"] | Omit = omit, - specifiers: Optional[Iterable[CommitSpecifierInput]] | Omit = omit, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractEditCreditResponse: - """ - Edit details for a contract-level or customer-level credit. - - ### Use this endpoint to: - - - Extend the duration or the amount of an existing free credit like a trial - - Modify individual credit access schedules, applicable products, priority, or - other fields. - - ### Usage guidelines: - - - As with all edits in Metronome, draft invoices will reflect the edit - immediately, while finalized invoices are untouched unless voided and - regenerated. - - You cannot remove an access schedule segment that was applied to a finalized - invoice. You can void the invoice beforehand and then remove the access - schedule segment. - - Args: - credit_id: ID of the credit to edit - - customer_id: ID of the customer whose credit is being edited - - applicable_product_ids: Which products the credit applies to. If both applicable_product_ids and - applicable_product_tags are not provided, the credit applies to all products. - - applicable_product_tags: Which tags the credit applies to. If both applicable_product_ids and - applicable_product_tags are not provided, the credit applies to all products. - - description: Updated description for the credit - - hierarchy_configuration: Optional configuration for credit hierarchy access control - - name: Updated name for the credit - - priority: If multiple commits are applicable, the one with the lower priority will apply - first. - - rate_type: If provided, updates the credit to use the specified rate type for current and - future invoices. Previously finalized invoices will need to be voided and - regenerated to reflect the rate type change. - - specifiers: List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - Instead, to target usage by product or product tag, pass those values in the - body of `specifiers`. - - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v2/contracts/credits/edit", - body=await async_maybe_transform( - { - "credit_id": credit_id, - "customer_id": customer_id, - "access_schedule": access_schedule, - "applicable_product_ids": applicable_product_ids, - "applicable_product_tags": applicable_product_tags, - "description": description, - "hierarchy_configuration": hierarchy_configuration, - "name": name, - "priority": priority, - "product_id": product_id, - "rate_type": rate_type, - "specifiers": specifiers, - }, - contract_edit_credit_params.ContractEditCreditParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractEditCreditResponse, - ) - - async def get_edit_history( - self, - *, - contract_id: str, - customer_id: str, - # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. - # The extra values given here take precedence over values defined on the client or passed to this method. - extra_headers: Headers | None = None, - extra_query: Query | None = None, - extra_body: Body | None = None, - timeout: float | httpx.Timeout | None | NotGiven = not_given, - ) -> ContractGetEditHistoryResponse: - """List all the edits made to a contract over time. - - In Metronome, you can edit a - contract at any point after it's created to fix mistakes or reflect changes in - terms. Metronome stores a full history of all edits that were ever made to a - contract, whether through the UI, `editContract` endpoint, or other endpoints - like `updateContractEndDate`. - - ### Use this endpoint to: - - - Understand what changes were made to a contract, when, and by who - - ### Key response fields: - - - An array of every edit ever made to the contract - - Details on each individual edit - for example showing that in one edit, a user - added two discounts and incremented a subscription quantity. - - Args: - extra_headers: Send extra headers - - extra_query: Add additional query parameters to the request - - extra_body: Add additional JSON properties to the request - - timeout: Override the client-level default timeout for this request, in seconds - """ - return await self._post( - "/v2/contracts/getEditHistory", - body=await async_maybe_transform( - { - "contract_id": contract_id, - "customer_id": customer_id, - }, - contract_get_edit_history_params.ContractGetEditHistoryParams, - ), - options=make_request_options( - extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout - ), - cast_to=ContractGetEditHistoryResponse, - ) - - -class ContractsResourceWithRawResponse: - def __init__(self, contracts: ContractsResource) -> None: - self._contracts = contracts - - self.retrieve = to_raw_response_wrapper( - contracts.retrieve, - ) - self.list = to_raw_response_wrapper( - contracts.list, - ) - self.edit = to_raw_response_wrapper( - contracts.edit, - ) - self.edit_commit = to_raw_response_wrapper( - contracts.edit_commit, - ) - self.edit_credit = to_raw_response_wrapper( - contracts.edit_credit, - ) - self.get_edit_history = to_raw_response_wrapper( - contracts.get_edit_history, - ) - - -class AsyncContractsResourceWithRawResponse: - def __init__(self, contracts: AsyncContractsResource) -> None: - self._contracts = contracts - - self.retrieve = async_to_raw_response_wrapper( - contracts.retrieve, - ) - self.list = async_to_raw_response_wrapper( - contracts.list, - ) - self.edit = async_to_raw_response_wrapper( - contracts.edit, - ) - self.edit_commit = async_to_raw_response_wrapper( - contracts.edit_commit, - ) - self.edit_credit = async_to_raw_response_wrapper( - contracts.edit_credit, - ) - self.get_edit_history = async_to_raw_response_wrapper( - contracts.get_edit_history, - ) - - -class ContractsResourceWithStreamingResponse: - def __init__(self, contracts: ContractsResource) -> None: - self._contracts = contracts - - self.retrieve = to_streamed_response_wrapper( - contracts.retrieve, - ) - self.list = to_streamed_response_wrapper( - contracts.list, - ) - self.edit = to_streamed_response_wrapper( - contracts.edit, - ) - self.edit_commit = to_streamed_response_wrapper( - contracts.edit_commit, - ) - self.edit_credit = to_streamed_response_wrapper( - contracts.edit_credit, - ) - self.get_edit_history = to_streamed_response_wrapper( - contracts.get_edit_history, - ) - - -class AsyncContractsResourceWithStreamingResponse: - def __init__(self, contracts: AsyncContractsResource) -> None: - self._contracts = contracts - - self.retrieve = async_to_streamed_response_wrapper( - contracts.retrieve, - ) - self.list = async_to_streamed_response_wrapper( - contracts.list, - ) - self.edit = async_to_streamed_response_wrapper( - contracts.edit, - ) - self.edit_commit = async_to_streamed_response_wrapper( - contracts.edit_commit, - ) - self.edit_credit = async_to_streamed_response_wrapper( - contracts.edit_credit, - ) - self.get_edit_history = async_to_streamed_response_wrapper( - contracts.get_edit_history, - ) diff --git a/src/metronome/resources/v2/v2.py b/src/metronome/resources/v2/v2.py deleted file mode 100644 index dbb4b305e..000000000 --- a/src/metronome/resources/v2/v2.py +++ /dev/null @@ -1,102 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from ..._compat import cached_property -from .contracts import ( - ContractsResource, - AsyncContractsResource, - ContractsResourceWithRawResponse, - AsyncContractsResourceWithRawResponse, - ContractsResourceWithStreamingResponse, - AsyncContractsResourceWithStreamingResponse, -) -from ..._resource import SyncAPIResource, AsyncAPIResource - -__all__ = ["V2Resource", "AsyncV2Resource"] - - -class V2Resource(SyncAPIResource): - @cached_property - def contracts(self) -> ContractsResource: - return ContractsResource(self._client) - - @cached_property - def with_raw_response(self) -> V2ResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return V2ResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> V2ResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return V2ResourceWithStreamingResponse(self) - - -class AsyncV2Resource(AsyncAPIResource): - @cached_property - def contracts(self) -> AsyncContractsResource: - return AsyncContractsResource(self._client) - - @cached_property - def with_raw_response(self) -> AsyncV2ResourceWithRawResponse: - """ - This property can be used as a prefix for any HTTP method call to return - the raw response object instead of the parsed content. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#accessing-raw-response-data-eg-headers - """ - return AsyncV2ResourceWithRawResponse(self) - - @cached_property - def with_streaming_response(self) -> AsyncV2ResourceWithStreamingResponse: - """ - An alternative to `.with_raw_response` that doesn't eagerly read the response body. - - For more information, see https://www.github.com/Metronome-Industries/metronome-python#with_streaming_response - """ - return AsyncV2ResourceWithStreamingResponse(self) - - -class V2ResourceWithRawResponse: - def __init__(self, v2: V2Resource) -> None: - self._v2 = v2 - - @cached_property - def contracts(self) -> ContractsResourceWithRawResponse: - return ContractsResourceWithRawResponse(self._v2.contracts) - - -class AsyncV2ResourceWithRawResponse: - def __init__(self, v2: AsyncV2Resource) -> None: - self._v2 = v2 - - @cached_property - def contracts(self) -> AsyncContractsResourceWithRawResponse: - return AsyncContractsResourceWithRawResponse(self._v2.contracts) - - -class V2ResourceWithStreamingResponse: - def __init__(self, v2: V2Resource) -> None: - self._v2 = v2 - - @cached_property - def contracts(self) -> ContractsResourceWithStreamingResponse: - return ContractsResourceWithStreamingResponse(self._v2.contracts) - - -class AsyncV2ResourceWithStreamingResponse: - def __init__(self, v2: AsyncV2Resource) -> None: - self._v2 = v2 - - @cached_property - def contracts(self) -> AsyncContractsResourceWithStreamingResponse: - return AsyncContractsResourceWithStreamingResponse(self._v2.contracts) diff --git a/src/metronome/types/__init__.py b/src/metronome/types/__init__.py deleted file mode 100644 index 4c91d3f67..000000000 --- a/src/metronome/types/__init__.py +++ /dev/null @@ -1,42 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .shared import ( - ID as ID, - Rate as Rate, - Tier as Tier, - Commit as Commit, - Credit as Credit, - Contract as Contract, - Discount as Discount, - Override as Override, - CommitRate as CommitRate, - ContractV2 as ContractV2, - ProService as ProService, - OverrideTier as OverrideTier, - Subscription as Subscription, - BalanceFilter as BalanceFilter, - OverwriteRate as OverwriteRate, - CreditTypeData as CreditTypeData, - PropertyFilter as PropertyFilter, - BaseUsageFilter as BaseUsageFilter, - CommitSpecifier as CommitSpecifier, - EventTypeFilter as EventTypeFilter, - ScheduledCharge as ScheduledCharge, - ScheduleDuration as ScheduleDuration, - PaymentGateConfig as PaymentGateConfig, - BaseThresholdCommit as BaseThresholdCommit, - PaymentGateConfigV2 as PaymentGateConfigV2, - SchedulePointInTime as SchedulePointInTime, - CommitSpecifierInput as CommitSpecifierInput, - HierarchyConfiguration as HierarchyConfiguration, - ContractWithoutAmendments as ContractWithoutAmendments, - UpdateBaseThresholdCommit as UpdateBaseThresholdCommit, - SpendThresholdConfiguration as SpendThresholdConfiguration, - CommitHierarchyConfiguration as CommitHierarchyConfiguration, - SpendThresholdConfigurationV2 as SpendThresholdConfigurationV2, - RecurringCommitSubscriptionConfig as RecurringCommitSubscriptionConfig, - PrepaidBalanceThresholdConfiguration as PrepaidBalanceThresholdConfiguration, - PrepaidBalanceThresholdConfigurationV2 as PrepaidBalanceThresholdConfigurationV2, -) diff --git a/src/metronome/types/shared/__init__.py b/src/metronome/types/shared/__init__.py deleted file mode 100644 index 4dc775596..000000000 --- a/src/metronome/types/shared/__init__.py +++ /dev/null @@ -1,42 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .id import ID as ID -from .rate import Rate as Rate -from .tier import Tier as Tier -from .commit import Commit as Commit -from .credit import Credit as Credit -from .contract import Contract as Contract -from .discount import Discount as Discount -from .override import Override as Override -from .commit_rate import CommitRate as CommitRate -from .contract_v2 import ContractV2 as ContractV2 -from .pro_service import ProService as ProService -from .subscription import Subscription as Subscription -from .override_tier import OverrideTier as OverrideTier -from .balance_filter import BalanceFilter as BalanceFilter -from .overwrite_rate import OverwriteRate as OverwriteRate -from .property_filter import PropertyFilter as PropertyFilter -from .commit_specifier import CommitSpecifier as CommitSpecifier -from .credit_type_data import CreditTypeData as CreditTypeData -from .scheduled_charge import ScheduledCharge as ScheduledCharge -from .base_usage_filter import BaseUsageFilter as BaseUsageFilter -from .event_type_filter import EventTypeFilter as EventTypeFilter -from .schedule_duration import ScheduleDuration as ScheduleDuration -from .payment_gate_config import PaymentGateConfig as PaymentGateConfig -from .base_threshold_commit import BaseThresholdCommit as BaseThresholdCommit -from .commit_specifier_input import CommitSpecifierInput as CommitSpecifierInput -from .payment_gate_config_v2 import PaymentGateConfigV2 as PaymentGateConfigV2 -from .schedule_point_in_time import SchedulePointInTime as SchedulePointInTime -from .hierarchy_configuration import HierarchyConfiguration as HierarchyConfiguration -from .contract_without_amendments import ContractWithoutAmendments as ContractWithoutAmendments -from .update_base_threshold_commit import UpdateBaseThresholdCommit as UpdateBaseThresholdCommit -from .spend_threshold_configuration import SpendThresholdConfiguration as SpendThresholdConfiguration -from .commit_hierarchy_configuration import CommitHierarchyConfiguration as CommitHierarchyConfiguration -from .spend_threshold_configuration_v2 import SpendThresholdConfigurationV2 as SpendThresholdConfigurationV2 -from .recurring_commit_subscription_config import RecurringCommitSubscriptionConfig as RecurringCommitSubscriptionConfig -from .prepaid_balance_threshold_configuration import ( - PrepaidBalanceThresholdConfiguration as PrepaidBalanceThresholdConfiguration, -) -from .prepaid_balance_threshold_configuration_v2 import ( - PrepaidBalanceThresholdConfigurationV2 as PrepaidBalanceThresholdConfigurationV2, -) diff --git a/src/metronome/types/shared/balance_filter.py b/src/metronome/types/shared/balance_filter.py deleted file mode 100644 index 092eb54e6..000000000 --- a/src/metronome/types/shared/balance_filter.py +++ /dev/null @@ -1,19 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["BalanceFilter"] - - -class BalanceFilter(BaseModel): - balance_types: Optional[List[Literal["PREPAID_COMMIT", "POSTPAID_COMMIT", "CREDIT"]]] = None - """The balance type to filter by.""" - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to compute balance across. Must match all custom fields""" - - ids: Optional[List[str]] = None - """Specific IDs to compute balance across.""" diff --git a/src/metronome/types/shared/base_threshold_commit.py b/src/metronome/types/shared/base_threshold_commit.py deleted file mode 100644 index 3f8dda4c1..000000000 --- a/src/metronome/types/shared/base_threshold_commit.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ..._models import BaseModel - -__all__ = ["BaseThresholdCommit"] - - -class BaseThresholdCommit(BaseModel): - product_id: str - """ - The commit product that will be used to generate the line item for commit - payment. - """ - - description: Optional[str] = None - - name: Optional[str] = None - """Specify the name of the line item for the threshold charge. - - If left blank, it will default to the commit product name. - """ diff --git a/src/metronome/types/shared/base_usage_filter.py b/src/metronome/types/shared/base_usage_filter.py deleted file mode 100644 index 6edf69adc..000000000 --- a/src/metronome/types/shared/base_usage_filter.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime - -from ..._models import BaseModel - -__all__ = ["BaseUsageFilter"] - - -class BaseUsageFilter(BaseModel): - group_key: str - - group_values: List[str] - - starting_at: Optional[datetime] = None diff --git a/src/metronome/types/shared/commit.py b/src/metronome/types/shared/commit.py deleted file mode 100644 index 7aae25236..000000000 --- a/src/metronome/types/shared/commit.py +++ /dev/null @@ -1,370 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from datetime import datetime -from typing_extensions import Literal, TypeAlias - -from ..._models import BaseModel -from .commit_specifier import CommitSpecifier -from .schedule_duration import ScheduleDuration -from .schedule_point_in_time import SchedulePointInTime -from .commit_hierarchy_configuration import CommitHierarchyConfiguration - -__all__ = [ - "Commit", - "Product", - "Contract", - "InvoiceContract", - "Ledger", - "LedgerPrepaidCommitSegmentStartLedgerEntry", - "LedgerPrepaidCommitAutomatedInvoiceDeductionLedgerEntry", - "LedgerPrepaidCommitRolloverLedgerEntry", - "LedgerPrepaidCommitExpirationLedgerEntry", - "LedgerPrepaidCommitCanceledLedgerEntry", - "LedgerPrepaidCommitCreditedLedgerEntry", - "LedgerPrepaidCommitSeatBasedAdjustmentLedgerEntry", - "LedgerPostpaidCommitInitialBalanceLedgerEntry", - "LedgerPostpaidCommitAutomatedInvoiceDeductionLedgerEntry", - "LedgerPostpaidCommitRolloverLedgerEntry", - "LedgerPostpaidCommitTrueupLedgerEntry", - "LedgerPrepaidCommitManualLedgerEntry", - "LedgerPostpaidCommitManualLedgerEntry", - "LedgerPostpaidCommitExpirationLedgerEntry", - "RolledOverFrom", - "SubscriptionConfig", - "SubscriptionConfigApplySeatIncreaseConfig", -] - - -class Product(BaseModel): - id: str - - name: str - - -class Contract(BaseModel): - id: str - - -class InvoiceContract(BaseModel): - """The contract that this commit will be billed on.""" - - id: str - - -class LedgerPrepaidCommitSegmentStartLedgerEntry(BaseModel): - amount: float - - segment_id: str - - timestamp: datetime - - type: Literal["PREPAID_COMMIT_SEGMENT_START"] - - -class LedgerPrepaidCommitAutomatedInvoiceDeductionLedgerEntry(BaseModel): - amount: float - - invoice_id: str - - segment_id: str - - timestamp: datetime - - type: Literal["PREPAID_COMMIT_AUTOMATED_INVOICE_DEDUCTION"] - - contract_id: Optional[str] = None - - -class LedgerPrepaidCommitRolloverLedgerEntry(BaseModel): - amount: float - - new_contract_id: str - - segment_id: str - - timestamp: datetime - - type: Literal["PREPAID_COMMIT_ROLLOVER"] - - -class LedgerPrepaidCommitExpirationLedgerEntry(BaseModel): - amount: float - - segment_id: str - - timestamp: datetime - - type: Literal["PREPAID_COMMIT_EXPIRATION"] - - -class LedgerPrepaidCommitCanceledLedgerEntry(BaseModel): - amount: float - - invoice_id: str - - segment_id: str - - timestamp: datetime - - type: Literal["PREPAID_COMMIT_CANCELED"] - - contract_id: Optional[str] = None - - -class LedgerPrepaidCommitCreditedLedgerEntry(BaseModel): - amount: float - - invoice_id: str - - segment_id: str - - timestamp: datetime - - type: Literal["PREPAID_COMMIT_CREDITED"] - - contract_id: Optional[str] = None - - -class LedgerPrepaidCommitSeatBasedAdjustmentLedgerEntry(BaseModel): - amount: float - - segment_id: str - - timestamp: datetime - - type: Literal["PREPAID_COMMIT_SEAT_BASED_ADJUSTMENT"] - - -class LedgerPostpaidCommitInitialBalanceLedgerEntry(BaseModel): - amount: float - - timestamp: datetime - - type: Literal["POSTPAID_COMMIT_INITIAL_BALANCE"] - - -class LedgerPostpaidCommitAutomatedInvoiceDeductionLedgerEntry(BaseModel): - amount: float - - invoice_id: str - - segment_id: str - - timestamp: datetime - - type: Literal["POSTPAID_COMMIT_AUTOMATED_INVOICE_DEDUCTION"] - - contract_id: Optional[str] = None - - -class LedgerPostpaidCommitRolloverLedgerEntry(BaseModel): - amount: float - - new_contract_id: str - - segment_id: str - - timestamp: datetime - - type: Literal["POSTPAID_COMMIT_ROLLOVER"] - - -class LedgerPostpaidCommitTrueupLedgerEntry(BaseModel): - amount: float - - invoice_id: str - - timestamp: datetime - - type: Literal["POSTPAID_COMMIT_TRUEUP"] - - contract_id: Optional[str] = None - - -class LedgerPrepaidCommitManualLedgerEntry(BaseModel): - amount: float - - reason: str - - timestamp: datetime - - type: Literal["PREPAID_COMMIT_MANUAL"] - - -class LedgerPostpaidCommitManualLedgerEntry(BaseModel): - amount: float - - reason: str - - timestamp: datetime - - type: Literal["POSTPAID_COMMIT_MANUAL"] - - -class LedgerPostpaidCommitExpirationLedgerEntry(BaseModel): - amount: float - - timestamp: datetime - - type: Literal["POSTPAID_COMMIT_EXPIRATION"] - - -Ledger: TypeAlias = Union[ - LedgerPrepaidCommitSegmentStartLedgerEntry, - LedgerPrepaidCommitAutomatedInvoiceDeductionLedgerEntry, - LedgerPrepaidCommitRolloverLedgerEntry, - LedgerPrepaidCommitExpirationLedgerEntry, - LedgerPrepaidCommitCanceledLedgerEntry, - LedgerPrepaidCommitCreditedLedgerEntry, - LedgerPrepaidCommitSeatBasedAdjustmentLedgerEntry, - LedgerPostpaidCommitInitialBalanceLedgerEntry, - LedgerPostpaidCommitAutomatedInvoiceDeductionLedgerEntry, - LedgerPostpaidCommitRolloverLedgerEntry, - LedgerPostpaidCommitTrueupLedgerEntry, - LedgerPrepaidCommitManualLedgerEntry, - LedgerPostpaidCommitManualLedgerEntry, - LedgerPostpaidCommitExpirationLedgerEntry, -] - - -class RolledOverFrom(BaseModel): - commit_id: str - - contract_id: str - - -class SubscriptionConfigApplySeatIncreaseConfig(BaseModel): - is_prorated: bool - """Indicates whether a mid-period seat increase should be prorated.""" - - -class SubscriptionConfig(BaseModel): - """ - The subscription configuration for this commit, if it was generated from a recurring commit with a subscription attached. - """ - - allocation: Optional[Literal["INDIVIDUAL", "POOLED"]] = None - - apply_seat_increase_config: Optional[SubscriptionConfigApplySeatIncreaseConfig] = None - - subscription_id: Optional[str] = None - - -class Commit(BaseModel): - id: str - - created_at: datetime - """Timestamp of when the commit was created. - - - Recurring commits: latter of commit service period date and parent commit - start date - - Rollover commits: when the new contract started - """ - - product: Product - - type: Literal["PREPAID", "POSTPAID"] - - access_schedule: Optional[ScheduleDuration] = None - """ - The schedule that the customer will gain access to the credits purposed with - this commit. - """ - - amount: Optional[float] = None - """(DEPRECATED) Use access_schedule + invoice_schedule instead.""" - - applicable_contract_ids: Optional[List[str]] = None - - applicable_product_ids: Optional[List[str]] = None - - applicable_product_tags: Optional[List[str]] = None - - archived_at: Optional[datetime] = None - """RFC 3339 timestamp indicating when the commit was archived. - - If not provided, the commit is not archived. - """ - - balance: Optional[float] = None - """The current balance of the credit or commit. - - This balance reflects the amount of credit or commit that the customer has - access to use at this moment - thus, expired and upcoming credit or commit - segments contribute 0 to the balance. The balance will match the sum of all - ledger entries with the exception of the case where the sum of negative manual - ledger entries exceeds the positive amount remaining on the credit or commit - - in that case, the balance will be 0. All manual ledger entries associated with - active credit or commit segments are included in the balance, including - future-dated manual ledger entries. - """ - - contract: Optional[Contract] = None - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: Optional[str] = None - - hierarchy_configuration: Optional[CommitHierarchyConfiguration] = None - """Optional configuration for commit hierarchy access control""" - - invoice_contract: Optional[InvoiceContract] = None - """The contract that this commit will be billed on.""" - - invoice_schedule: Optional[SchedulePointInTime] = None - """The schedule that the customer will be invoiced for this commit.""" - - ledger: Optional[List[Ledger]] = None - """A list of ordered events that impact the balance of a commit. - - For example, an invoice deduction or a rollover. - """ - - name: Optional[str] = None - - netsuite_sales_order_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - priority: Optional[float] = None - """ - If multiple credits or commits are applicable, the one with the lower priority - will apply first. - """ - - rate_type: Optional[Literal["COMMIT_RATE", "LIST_RATE"]] = None - - recurring_commit_id: Optional[str] = None - """ - The ID of the recurring commit that this commit was generated from, if - applicable. - """ - - rolled_over_from: Optional[RolledOverFrom] = None - - rollover_fraction: Optional[float] = None - - salesforce_opportunity_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - specifiers: Optional[List[CommitSpecifier]] = None - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. - """ - - subscription_config: Optional[SubscriptionConfig] = None - """ - The subscription configuration for this commit, if it was generated from a - recurring commit with a subscription attached. - """ - - uniqueness_key: Optional[str] = None - """Prevents the creation of duplicates. - - If a request to create a commit or credit is made with a uniqueness key that was - previously used to create a commit or credit, a new record will not be created - and the request will fail with a 409 error. - """ diff --git a/src/metronome/types/shared/commit_hierarchy_configuration.py b/src/metronome/types/shared/commit_hierarchy_configuration.py deleted file mode 100644 index f46375473..000000000 --- a/src/metronome/types/shared/commit_hierarchy_configuration.py +++ /dev/null @@ -1,39 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union -from typing_extensions import Literal, TypeAlias - -from ..._models import BaseModel - -__all__ = [ - "CommitHierarchyConfiguration", - "ChildAccess", - "ChildAccessCommitHierarchyChildAccessAll", - "ChildAccessCommitHierarchyChildAccessNone", - "ChildAccessCommitHierarchyChildAccessContractIDs", -] - - -class ChildAccessCommitHierarchyChildAccessAll(BaseModel): - type: Literal["ALL"] - - -class ChildAccessCommitHierarchyChildAccessNone(BaseModel): - type: Literal["NONE"] - - -class ChildAccessCommitHierarchyChildAccessContractIDs(BaseModel): - contract_ids: List[str] - - type: Literal["CONTRACT_IDS"] - - -ChildAccess: TypeAlias = Union[ - ChildAccessCommitHierarchyChildAccessAll, - ChildAccessCommitHierarchyChildAccessNone, - ChildAccessCommitHierarchyChildAccessContractIDs, -] - - -class CommitHierarchyConfiguration(BaseModel): - child_access: ChildAccess diff --git a/src/metronome/types/shared/commit_rate.py b/src/metronome/types/shared/commit_rate.py deleted file mode 100644 index 859207d4c..000000000 --- a/src/metronome/types/shared/commit_rate.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from .tier import Tier -from ..._models import BaseModel - -__all__ = ["CommitRate"] - - -class CommitRate(BaseModel): - """A distinct rate on the rate card. - - You can choose to use this rate rather than list rate when consuming a credit or commit. - """ - - rate_type: Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "TIERED", "TIERED_PERCENTAGE", "CUSTOM"] - - price: Optional[float] = None - """Commit rate price. - - For FLAT rate_type, this must be >=0. For PERCENTAGE rate_type, this is a - decimal fraction, e.g. use 0.1 for 10%; this must be >=0 and <=1. - """ - - tiers: Optional[List[Tier]] = None - """Only set for TIERED rate_type.""" diff --git a/src/metronome/types/shared/commit_specifier.py b/src/metronome/types/shared/commit_specifier.py deleted file mode 100644 index 1c09b068d..000000000 --- a/src/metronome/types/shared/commit_specifier.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional - -from ..._models import BaseModel - -__all__ = ["CommitSpecifier"] - - -class CommitSpecifier(BaseModel): - presentation_group_values: Optional[Dict[str, str]] = None - - pricing_group_values: Optional[Dict[str, str]] = None - - product_id: Optional[str] = None - """ - If provided, the specifier will only apply to the product with the specified ID. - """ - - product_tags: Optional[List[str]] = None - """ - If provided, the specifier will only apply to products with all the specified - tags. - """ diff --git a/src/metronome/types/shared/commit_specifier_input.py b/src/metronome/types/shared/commit_specifier_input.py deleted file mode 100644 index fa745a9c7..000000000 --- a/src/metronome/types/shared/commit_specifier_input.py +++ /dev/null @@ -1,32 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional - -from ..._models import BaseModel - -__all__ = ["CommitSpecifierInput"] - - -class CommitSpecifierInput(BaseModel): - presentation_group_values: Optional[Dict[str, str]] = None - """ - If provided, the specifier will apply to product usage with these set of - presentation group values. - """ - - pricing_group_values: Optional[Dict[str, str]] = None - """ - If provided, the specifier will apply to product usage with these set of pricing - group values. - """ - - product_id: Optional[str] = None - """ - If provided, the specifier will only apply to the product with the specified ID. - """ - - product_tags: Optional[List[str]] = None - """ - If provided, the specifier will only apply to products with all the specified - tags. - """ diff --git a/src/metronome/types/shared/contract.py b/src/metronome/types/shared/contract.py deleted file mode 100644 index 5a4f386ac..000000000 --- a/src/metronome/types/shared/contract.py +++ /dev/null @@ -1,154 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from datetime import datetime -from typing_extensions import Literal - -from .commit import Commit -from .credit import Credit -from .discount import Discount -from .override import Override -from ..._models import BaseModel -from .pro_service import ProService -from .subscription import Subscription -from .scheduled_charge import ScheduledCharge -from .contract_without_amendments import ContractWithoutAmendments -from .spend_threshold_configuration import SpendThresholdConfiguration -from .prepaid_balance_threshold_configuration import PrepaidBalanceThresholdConfiguration - -__all__ = ["Contract", "Amendment", "AmendmentResellerRoyalty", "CustomerBillingProviderConfiguration"] - - -class AmendmentResellerRoyalty(BaseModel): - reseller_type: Literal["AWS", "AWS_PRO_SERVICE", "GCP", "GCP_PRO_SERVICE"] - - aws_account_number: Optional[str] = None - - aws_offer_id: Optional[str] = None - - aws_payer_reference_id: Optional[str] = None - - ending_before: Optional[datetime] = None - - fraction: Optional[float] = None - - gcp_account_id: Optional[str] = None - - gcp_offer_id: Optional[str] = None - - netsuite_reseller_id: Optional[str] = None - - reseller_contract_value: Optional[float] = None - - starting_at: Optional[datetime] = None - - -class Amendment(BaseModel): - id: str - - commits: List[Commit] - - created_at: datetime - - created_by: str - - overrides: List[Override] - - scheduled_charges: List[ScheduledCharge] - - starting_at: datetime - - credits: Optional[List[Credit]] = None - - discounts: Optional[List[Discount]] = None - """This field's availability is dependent on your client's configuration.""" - - netsuite_sales_order_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - professional_services: Optional[List[ProService]] = None - """This field's availability is dependent on your client's configuration.""" - - reseller_royalties: Optional[List[AmendmentResellerRoyalty]] = None - """This field's availability is dependent on your client's configuration.""" - - salesforce_opportunity_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - -class CustomerBillingProviderConfiguration(BaseModel): - """The billing provider configuration associated with a contract.""" - - archived_at: Optional[datetime] = None - - billing_provider: Literal[ - "aws_marketplace", - "stripe", - "netsuite", - "custom", - "azure_marketplace", - "quickbooks_online", - "workday", - "gcp_marketplace", - "metronome", - ] - - delivery_method: Literal["direct_to_billing_provider", "aws_sqs", "tackle", "aws_sns"] - - id: Optional[str] = None - - configuration: Optional[Dict[str, object]] = None - """Configuration for the billing provider. - - The structure of this object is specific to the billing provider. - """ - - -class Contract(BaseModel): - id: str - - amendments: List[Amendment] - - current: ContractWithoutAmendments - - customer_id: str - - initial: ContractWithoutAmendments - - archived_at: Optional[datetime] = None - """RFC 3339 timestamp indicating when the contract was archived. - - If not returned, the contract is not archived. - """ - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - customer_billing_provider_configuration: Optional[CustomerBillingProviderConfiguration] = None - """The billing provider configuration associated with a contract.""" - - package_id: Optional[str] = None - """ID of the package this contract was created from, if applicable.""" - - prepaid_balance_threshold_configuration: Optional[PrepaidBalanceThresholdConfiguration] = None - - scheduled_charges_on_usage_invoices: Optional[Literal["ALL"]] = None - """ - Determines which scheduled and commit charges to consolidate onto the Contract's - usage invoice. The charge's `timestamp` must match the usage invoice's - `ending_before` date for consolidation to occur. This field cannot be modified - after a Contract has been created. If this field is omitted, charges will appear - on a separate invoice from usage charges. - """ - - spend_threshold_configuration: Optional[SpendThresholdConfiguration] = None - - subscriptions: Optional[List[Subscription]] = None - """List of subscriptions on the contract.""" - - uniqueness_key: Optional[str] = None - """Prevents the creation of duplicates. - - If a request to create a record is made with a previously used uniqueness key, a - new record will not be created and the request will fail with a 409 error. - """ diff --git a/src/metronome/types/shared/contract_v2.py b/src/metronome/types/shared/contract_v2.py deleted file mode 100644 index 3894d1199..000000000 --- a/src/metronome/types/shared/contract_v2.py +++ /dev/null @@ -1,1150 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from datetime import datetime -from typing_extensions import Literal, TypeAlias - -from .tier import Tier -from .discount import Discount -from ..._models import BaseModel -from .pro_service import ProService -from .subscription import Subscription -from .override_tier import OverrideTier -from .commit_specifier import CommitSpecifier -from .credit_type_data import CreditTypeData -from .scheduled_charge import ScheduledCharge -from .schedule_duration import ScheduleDuration -from .schedule_point_in_time import SchedulePointInTime -from .commit_hierarchy_configuration import CommitHierarchyConfiguration -from .spend_threshold_configuration_v2 import SpendThresholdConfigurationV2 -from .recurring_commit_subscription_config import RecurringCommitSubscriptionConfig -from .prepaid_balance_threshold_configuration_v2 import PrepaidBalanceThresholdConfigurationV2 - -__all__ = [ - "ContractV2", - "Commit", - "CommitProduct", - "CommitContract", - "CommitInvoiceContract", - "CommitLedger", - "CommitLedgerPrepaidCommitSegmentStartLedgerEntry", - "CommitLedgerPrepaidCommitAutomatedInvoiceDeductionLedgerEntry", - "CommitLedgerPrepaidCommitRolloverLedgerEntry", - "CommitLedgerPrepaidCommitExpirationLedgerEntry", - "CommitLedgerPrepaidCommitCanceledLedgerEntry", - "CommitLedgerPrepaidCommitCreditedLedgerEntry", - "CommitLedgerPrepaidCommitSeatBasedAdjustmentLedgerEntry", - "CommitLedgerPostpaidCommitInitialBalanceLedgerEntry", - "CommitLedgerPostpaidCommitAutomatedInvoiceDeductionLedgerEntry", - "CommitLedgerPostpaidCommitRolloverLedgerEntry", - "CommitLedgerPostpaidCommitTrueupLedgerEntry", - "CommitLedgerPrepaidCommitManualLedgerEntry", - "CommitLedgerPostpaidCommitManualLedgerEntry", - "CommitLedgerPostpaidCommitExpirationLedgerEntry", - "CommitRolledOverFrom", - "Override", - "OverrideOverrideSpecifier", - "OverrideOverwriteRate", - "OverrideProduct", - "Transition", - "UsageFilter", - "UsageStatementSchedule", - "Credit", - "CreditProduct", - "CreditContract", - "CreditLedger", - "CreditLedgerCreditSegmentStartLedgerEntry", - "CreditLedgerCreditAutomatedInvoiceDeductionLedgerEntry", - "CreditLedgerCreditExpirationLedgerEntry", - "CreditLedgerCreditCanceledLedgerEntry", - "CreditLedgerCreditCreditedLedgerEntry", - "CreditLedgerCreditManualLedgerEntry", - "CreditLedgerCreditSeatBasedAdjustmentLedgerEntry", - "CustomerBillingProviderConfiguration", - "HasMore", - "HierarchyConfiguration", - "HierarchyConfigurationParentHierarchyConfiguration", - "HierarchyConfigurationParentHierarchyConfigurationChild", - "HierarchyConfigurationParentHierarchyConfigurationParentBehavior", - "HierarchyConfigurationChildHierarchyConfigurationV2", - "HierarchyConfigurationChildHierarchyConfigurationV2Parent", - "RecurringCommit", - "RecurringCommitAccessAmount", - "RecurringCommitCommitDuration", - "RecurringCommitProduct", - "RecurringCommitContract", - "RecurringCommitInvoiceAmount", - "RecurringCredit", - "RecurringCreditAccessAmount", - "RecurringCreditCommitDuration", - "RecurringCreditProduct", - "RecurringCreditContract", - "ResellerRoyalty", - "ResellerRoyaltySegment", -] - - -class CommitProduct(BaseModel): - id: str - - name: str - - -class CommitContract(BaseModel): - id: str - - -class CommitInvoiceContract(BaseModel): - """The contract that this commit will be billed on.""" - - id: str - - -class CommitLedgerPrepaidCommitSegmentStartLedgerEntry(BaseModel): - amount: float - - segment_id: str - - timestamp: datetime - - type: Literal["PREPAID_COMMIT_SEGMENT_START"] - - -class CommitLedgerPrepaidCommitAutomatedInvoiceDeductionLedgerEntry(BaseModel): - amount: float - - invoice_id: str - - segment_id: str - - timestamp: datetime - - type: Literal["PREPAID_COMMIT_AUTOMATED_INVOICE_DEDUCTION"] - - contract_id: Optional[str] = None - - -class CommitLedgerPrepaidCommitRolloverLedgerEntry(BaseModel): - amount: float - - new_contract_id: str - - segment_id: str - - timestamp: datetime - - type: Literal["PREPAID_COMMIT_ROLLOVER"] - - -class CommitLedgerPrepaidCommitExpirationLedgerEntry(BaseModel): - amount: float - - segment_id: str - - timestamp: datetime - - type: Literal["PREPAID_COMMIT_EXPIRATION"] - - -class CommitLedgerPrepaidCommitCanceledLedgerEntry(BaseModel): - amount: float - - invoice_id: str - - segment_id: str - - timestamp: datetime - - type: Literal["PREPAID_COMMIT_CANCELED"] - - contract_id: Optional[str] = None - - -class CommitLedgerPrepaidCommitCreditedLedgerEntry(BaseModel): - amount: float - - invoice_id: str - - segment_id: str - - timestamp: datetime - - type: Literal["PREPAID_COMMIT_CREDITED"] - - contract_id: Optional[str] = None - - -class CommitLedgerPrepaidCommitSeatBasedAdjustmentLedgerEntry(BaseModel): - amount: float - - segment_id: str - - timestamp: datetime - - type: Literal["PREPAID_COMMIT_SEAT_BASED_ADJUSTMENT"] - - -class CommitLedgerPostpaidCommitInitialBalanceLedgerEntry(BaseModel): - amount: float - - timestamp: datetime - - type: Literal["POSTPAID_COMMIT_INITIAL_BALANCE"] - - -class CommitLedgerPostpaidCommitAutomatedInvoiceDeductionLedgerEntry(BaseModel): - amount: float - - invoice_id: str - - segment_id: str - - timestamp: datetime - - type: Literal["POSTPAID_COMMIT_AUTOMATED_INVOICE_DEDUCTION"] - - contract_id: Optional[str] = None - - -class CommitLedgerPostpaidCommitRolloverLedgerEntry(BaseModel): - amount: float - - new_contract_id: str - - segment_id: str - - timestamp: datetime - - type: Literal["POSTPAID_COMMIT_ROLLOVER"] - - -class CommitLedgerPostpaidCommitTrueupLedgerEntry(BaseModel): - amount: float - - invoice_id: str - - timestamp: datetime - - type: Literal["POSTPAID_COMMIT_TRUEUP"] - - contract_id: Optional[str] = None - - -class CommitLedgerPrepaidCommitManualLedgerEntry(BaseModel): - amount: float - - reason: str - - timestamp: datetime - - type: Literal["PREPAID_COMMIT_MANUAL"] - - -class CommitLedgerPostpaidCommitManualLedgerEntry(BaseModel): - amount: float - - reason: str - - timestamp: datetime - - type: Literal["POSTPAID_COMMIT_MANUAL"] - - -class CommitLedgerPostpaidCommitExpirationLedgerEntry(BaseModel): - amount: float - - timestamp: datetime - - type: Literal["POSTPAID_COMMIT_EXPIRATION"] - - -CommitLedger: TypeAlias = Union[ - CommitLedgerPrepaidCommitSegmentStartLedgerEntry, - CommitLedgerPrepaidCommitAutomatedInvoiceDeductionLedgerEntry, - CommitLedgerPrepaidCommitRolloverLedgerEntry, - CommitLedgerPrepaidCommitExpirationLedgerEntry, - CommitLedgerPrepaidCommitCanceledLedgerEntry, - CommitLedgerPrepaidCommitCreditedLedgerEntry, - CommitLedgerPrepaidCommitSeatBasedAdjustmentLedgerEntry, - CommitLedgerPostpaidCommitInitialBalanceLedgerEntry, - CommitLedgerPostpaidCommitAutomatedInvoiceDeductionLedgerEntry, - CommitLedgerPostpaidCommitRolloverLedgerEntry, - CommitLedgerPostpaidCommitTrueupLedgerEntry, - CommitLedgerPrepaidCommitManualLedgerEntry, - CommitLedgerPostpaidCommitManualLedgerEntry, - CommitLedgerPostpaidCommitExpirationLedgerEntry, -] - - -class CommitRolledOverFrom(BaseModel): - commit_id: str - - contract_id: str - - -class Commit(BaseModel): - id: str - - created_at: datetime - """Timestamp of when the commit was created. - - - Recurring commits: latter of commit service period date and parent commit - start date - - Rollover commits: when the new contract started - """ - - product: CommitProduct - - type: Literal["PREPAID", "POSTPAID"] - - access_schedule: Optional[ScheduleDuration] = None - """ - The schedule that the customer will gain access to the credits purposed with - this commit. - """ - - applicable_contract_ids: Optional[List[str]] = None - - applicable_product_ids: Optional[List[str]] = None - - applicable_product_tags: Optional[List[str]] = None - - archived_at: Optional[datetime] = None - - balance: Optional[float] = None - """The current balance of the credit or commit. - - This balance reflects the amount of credit or commit that the customer has - access to use at this moment - thus, expired and upcoming credit or commit - segments contribute 0 to the balance. The balance will match the sum of all - ledger entries with the exception of the case where the sum of negative manual - ledger entries exceeds the positive amount remaining on the credit or commit - - in that case, the balance will be 0. All manual ledger entries associated with - active credit or commit segments are included in the balance, including - future-dated manual ledger entries. - """ - - contract: Optional[CommitContract] = None - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: Optional[str] = None - - hierarchy_configuration: Optional[CommitHierarchyConfiguration] = None - """Optional configuration for commit hierarchy access control""" - - invoice_contract: Optional[CommitInvoiceContract] = None - """The contract that this commit will be billed on.""" - - invoice_schedule: Optional[SchedulePointInTime] = None - """The schedule that the customer will be invoiced for this commit.""" - - ledger: Optional[List[CommitLedger]] = None - """A list of ordered events that impact the balance of a commit. - - For example, an invoice deduction or a rollover. - """ - - name: Optional[str] = None - - netsuite_sales_order_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - priority: Optional[float] = None - """ - If multiple credits or commits are applicable, the one with the lower priority - will apply first. - """ - - rate_type: Optional[Literal["COMMIT_RATE", "LIST_RATE"]] = None - - recurring_commit_id: Optional[str] = None - """The ID of the recurring commit that created this commit""" - - rolled_over_from: Optional[CommitRolledOverFrom] = None - - rollover_fraction: Optional[float] = None - - salesforce_opportunity_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - specifiers: Optional[List[CommitSpecifier]] = None - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. - """ - - subscription_config: Optional[RecurringCommitSubscriptionConfig] = None - """Attach a subscription to the recurring commit/credit.""" - - -class OverrideOverrideSpecifier(BaseModel): - billing_frequency: Optional[Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"]] = None - - commit_ids: Optional[List[str]] = None - - presentation_group_values: Optional[Dict[str, Optional[str]]] = None - - pricing_group_values: Optional[Dict[str, str]] = None - - product_id: Optional[str] = None - - product_tags: Optional[List[str]] = None - - recurring_commit_ids: Optional[List[str]] = None - - recurring_credit_ids: Optional[List[str]] = None - - -class OverrideOverwriteRate(BaseModel): - rate_type: Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "TIERED", "TIERED_PERCENTAGE", "CUSTOM"] - - credit_type: Optional[CreditTypeData] = None - - custom_rate: Optional[Dict[str, object]] = None - """Only set for CUSTOM rate_type. - - This field is interpreted by custom rate processors. - """ - - is_prorated: Optional[bool] = None - """Default proration configuration. - - Only valid for SUBSCRIPTION rate_type. Must be set to true. - """ - - price: Optional[float] = None - """Default price. - - For FLAT rate_type, this must be >=0. For PERCENTAGE rate_type, this is a - decimal fraction, e.g. use 0.1 for 10%; this must be >=0 and <=1. - """ - - quantity: Optional[float] = None - """Default quantity. For SUBSCRIPTION rate_type, this must be >=0.""" - - tiers: Optional[List[Tier]] = None - """Only set for TIERED rate_type.""" - - -class OverrideProduct(BaseModel): - id: str - - name: str - - -class Override(BaseModel): - id: str - - starting_at: datetime - - applicable_product_tags: Optional[List[str]] = None - - ending_before: Optional[datetime] = None - - entitled: Optional[bool] = None - - is_commit_specific: Optional[bool] = None - - multiplier: Optional[float] = None - - override_specifiers: Optional[List[OverrideOverrideSpecifier]] = None - - override_tiers: Optional[List[OverrideTier]] = None - - overwrite_rate: Optional[OverrideOverwriteRate] = None - - priority: Optional[float] = None - - product: Optional[OverrideProduct] = None - - target: Optional[Literal["COMMIT_RATE", "LIST_RATE"]] = None - - type: Optional[Literal["OVERWRITE", "MULTIPLIER", "TIERED"]] = None - - -class Transition(BaseModel): - from_contract_id: str - - to_contract_id: str - - type: Literal["SUPERSEDE", "RENEWAL"] - - -class UsageFilter(BaseModel): - group_key: str - - group_values: List[str] - - starting_at: datetime - """ - This will match contract starting_at value if usage filter is active from the - beginning of the contract. - """ - - ending_before: Optional[datetime] = None - """ - This will match contract ending_before value if usage filter is active until the - end of the contract. It will be undefined if the contract is open-ended. - """ - - -class UsageStatementSchedule(BaseModel): - billing_anchor_date: datetime - """Contract usage statements follow a selected cadence based on this date.""" - - frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"] - - -class CreditProduct(BaseModel): - id: str - - name: str - - -class CreditContract(BaseModel): - id: str - - -class CreditLedgerCreditSegmentStartLedgerEntry(BaseModel): - amount: float - - segment_id: str - - timestamp: datetime - - type: Literal["CREDIT_SEGMENT_START"] - - -class CreditLedgerCreditAutomatedInvoiceDeductionLedgerEntry(BaseModel): - amount: float - - invoice_id: str - - segment_id: str - - timestamp: datetime - - type: Literal["CREDIT_AUTOMATED_INVOICE_DEDUCTION"] - - contract_id: Optional[str] = None - - -class CreditLedgerCreditExpirationLedgerEntry(BaseModel): - amount: float - - segment_id: str - - timestamp: datetime - - type: Literal["CREDIT_EXPIRATION"] - - -class CreditLedgerCreditCanceledLedgerEntry(BaseModel): - amount: float - - invoice_id: str - - segment_id: str - - timestamp: datetime - - type: Literal["CREDIT_CANCELED"] - - contract_id: Optional[str] = None - - -class CreditLedgerCreditCreditedLedgerEntry(BaseModel): - amount: float - - invoice_id: str - - segment_id: str - - timestamp: datetime - - type: Literal["CREDIT_CREDITED"] - - contract_id: Optional[str] = None - - -class CreditLedgerCreditManualLedgerEntry(BaseModel): - amount: float - - reason: str - - timestamp: datetime - - type: Literal["CREDIT_MANUAL"] - - -class CreditLedgerCreditSeatBasedAdjustmentLedgerEntry(BaseModel): - amount: float - - segment_id: str - - timestamp: datetime - - type: Literal["CREDIT_SEAT_BASED_ADJUSTMENT"] - - -CreditLedger: TypeAlias = Union[ - CreditLedgerCreditSegmentStartLedgerEntry, - CreditLedgerCreditAutomatedInvoiceDeductionLedgerEntry, - CreditLedgerCreditExpirationLedgerEntry, - CreditLedgerCreditCanceledLedgerEntry, - CreditLedgerCreditCreditedLedgerEntry, - CreditLedgerCreditManualLedgerEntry, - CreditLedgerCreditSeatBasedAdjustmentLedgerEntry, -] - - -class Credit(BaseModel): - id: str - - product: CreditProduct - - type: Literal["CREDIT"] - - access_schedule: Optional[ScheduleDuration] = None - """The schedule that the customer will gain access to the credits.""" - - applicable_contract_ids: Optional[List[str]] = None - - applicable_product_ids: Optional[List[str]] = None - - applicable_product_tags: Optional[List[str]] = None - - balance: Optional[float] = None - """The current balance of the credit or commit. - - This balance reflects the amount of credit or commit that the customer has - access to use at this moment - thus, expired and upcoming credit or commit - segments contribute 0 to the balance. The balance will match the sum of all - ledger entries with the exception of the case where the sum of negative manual - ledger entries exceeds the positive amount remaining on the credit or commit - - in that case, the balance will be 0. All manual ledger entries associated with - active credit or commit segments are included in the balance, including - future-dated manual ledger entries. - """ - - contract: Optional[CreditContract] = None - - created_at: Optional[datetime] = None - """Timestamp of when the credit was created. - - - Recurring credits: latter of credit service period date and parent credit - start date - """ - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: Optional[str] = None - - hierarchy_configuration: Optional[CommitHierarchyConfiguration] = None - """Optional configuration for credit hierarchy access control""" - - ledger: Optional[List[CreditLedger]] = None - """A list of ordered events that impact the balance of a credit. - - For example, an invoice deduction or an expiration. - """ - - name: Optional[str] = None - - netsuite_sales_order_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - priority: Optional[float] = None - """ - If multiple credits or commits are applicable, the one with the lower priority - will apply first. - """ - - recurring_credit_id: Optional[str] = None - """The ID of the recurring credit that created this credit""" - - salesforce_opportunity_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - specifiers: Optional[List[CommitSpecifier]] = None - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. - """ - - subscription_config: Optional[RecurringCommitSubscriptionConfig] = None - """Attach a subscription to the recurring commit/credit.""" - - -class CustomerBillingProviderConfiguration(BaseModel): - """This field's availability is dependent on your client's configuration.""" - - id: str - """ID of Customer's billing provider configuration.""" - - billing_provider: Literal[ - "aws_marketplace", - "stripe", - "netsuite", - "custom", - "azure_marketplace", - "quickbooks_online", - "workday", - "gcp_marketplace", - "metronome", - ] - - delivery_method: Literal["direct_to_billing_provider", "aws_sqs", "tackle", "aws_sns"] - - -class HasMore(BaseModel): - """Indicates whether there are more items than the limit for this endpoint. - - Use the respective list endpoints to get the full lists. - """ - - commits: bool - """Whether there are more commits on this contract than the limit for this - endpoint. - - Use the /contracts/customerCommits/list endpoint to get the full list of - commits. - """ - - credits: bool - """Whether there are more credits on this contract than the limit for this - endpoint. - - Use the /contracts/customerCredits/list endpoint to get the full list of - credits. - """ - - -class HierarchyConfigurationParentHierarchyConfigurationChild(BaseModel): - contract_id: str - - customer_id: str - - -class HierarchyConfigurationParentHierarchyConfigurationParentBehavior(BaseModel): - invoice_consolidation_type: Optional[Literal["CONCATENATE", "NONE"]] = None - """ - Indicates the desired behavior of consolidated invoices generated by the parent - in a customer hierarchy - - **CONCATENATE**: Statements on the invoices of child customers will be appended - to the consolidated invoice - - **NONE**: Do not generate consolidated invoices - """ - - -class HierarchyConfigurationParentHierarchyConfiguration(BaseModel): - children: List[HierarchyConfigurationParentHierarchyConfigurationChild] - """List of contracts that belong to this parent.""" - - parent_behavior: Optional[HierarchyConfigurationParentHierarchyConfigurationParentBehavior] = None - - -class HierarchyConfigurationChildHierarchyConfigurationV2Parent(BaseModel): - """The single parent contract/customer for this child.""" - - contract_id: str - - customer_id: str - - -class HierarchyConfigurationChildHierarchyConfigurationV2(BaseModel): - parent: HierarchyConfigurationChildHierarchyConfigurationV2Parent - """The single parent contract/customer for this child.""" - - payer: Optional[Literal["SELF", "PARENT"]] = None - """ - Indicates which customer should pay for the child's invoice charges **SELF**: - The child pays for its own invoice charges **PARENT**: The parent pays for the - child's invoice charges - """ - - usage_statement_behavior: Optional[Literal["CONSOLIDATE", "SEPARATE"]] = None - """ - Indicates the behavior of the child's invoice statements on the parent's - invoices. - - **CONSOLIDATE**: Child's invoice statements will be added to parent's - consolidated invoices - - **SEPARATE**: Child's invoice statements will appear not appear on parent's - consolidated invoices - """ - - -HierarchyConfiguration: TypeAlias = Union[ - HierarchyConfigurationParentHierarchyConfiguration, HierarchyConfigurationChildHierarchyConfigurationV2 -] - - -class RecurringCommitAccessAmount(BaseModel): - """The amount of commit to grant.""" - - credit_type_id: str - - unit_price: float - - quantity: Optional[float] = None - - -class RecurringCommitCommitDuration(BaseModel): - """The amount of time the created commits will be valid for""" - - value: float - - unit: Optional[Literal["PERIODS"]] = None - - -class RecurringCommitProduct(BaseModel): - id: str - - name: str - - -class RecurringCommitContract(BaseModel): - id: str - - -class RecurringCommitInvoiceAmount(BaseModel): - """The amount the customer should be billed for the commit. Not required.""" - - credit_type_id: str - - quantity: float - - unit_price: float - - -class RecurringCommit(BaseModel): - id: str - - access_amount: RecurringCommitAccessAmount - """The amount of commit to grant.""" - - commit_duration: RecurringCommitCommitDuration - """The amount of time the created commits will be valid for""" - - priority: float - """Will be passed down to the individual commits""" - - product: RecurringCommitProduct - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - """Whether the created commits will use the commit rate or list rate""" - - starting_at: datetime - """Determines the start time for the first commit""" - - applicable_product_ids: Optional[List[str]] = None - """Will be passed down to the individual commits""" - - applicable_product_tags: Optional[List[str]] = None - """Will be passed down to the individual commits""" - - contract: Optional[RecurringCommitContract] = None - - description: Optional[str] = None - """Will be passed down to the individual commits""" - - ending_before: Optional[datetime] = None - """Determines when the contract will stop creating recurring commits. Optional""" - - hierarchy_configuration: Optional[CommitHierarchyConfiguration] = None - """Optional configuration for recurring credit hierarchy access control""" - - invoice_amount: Optional[RecurringCommitInvoiceAmount] = None - """The amount the customer should be billed for the commit. Not required.""" - - name: Optional[str] = None - """Displayed on invoices. Will be passed through to the individual commits""" - - netsuite_sales_order_id: Optional[str] = None - """Will be passed down to the individual commits""" - - proration: Optional[Literal["NONE", "FIRST", "LAST", "FIRST_AND_LAST"]] = None - """Determines whether the first and last commit will be prorated. - - If not provided, the default is FIRST_AND_LAST (i.e. prorate both the first and - last commits). - """ - - recurrence_frequency: Optional[Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"]] = None - """The frequency at which the recurring commits will be created. - - If not provided: - The commits will be created on the usage invoice frequency. - If provided: - The period defined in the duration will correspond to this - frequency. - Commits will be created aligned with the recurring commit's - starting_at rather than the usage invoice dates. - """ - - rollover_fraction: Optional[float] = None - """Will be passed down to the individual commits. - - This controls how much of an individual unexpired commit will roll over upon - contract transition. Must be between 0 and 1. - """ - - specifiers: Optional[List[CommitSpecifier]] = None - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. - """ - - subscription_config: Optional[RecurringCommitSubscriptionConfig] = None - """Attach a subscription to the recurring commit/credit.""" - - -class RecurringCreditAccessAmount(BaseModel): - """The amount of commit to grant.""" - - credit_type_id: str - - unit_price: float - - quantity: Optional[float] = None - - -class RecurringCreditCommitDuration(BaseModel): - """The amount of time the created commits will be valid for""" - - value: float - - unit: Optional[Literal["PERIODS"]] = None - - -class RecurringCreditProduct(BaseModel): - id: str - - name: str - - -class RecurringCreditContract(BaseModel): - id: str - - -class RecurringCredit(BaseModel): - id: str - - access_amount: RecurringCreditAccessAmount - """The amount of commit to grant.""" - - commit_duration: RecurringCreditCommitDuration - """The amount of time the created commits will be valid for""" - - priority: float - """Will be passed down to the individual commits""" - - product: RecurringCreditProduct - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - """Whether the created commits will use the commit rate or list rate""" - - starting_at: datetime - """Determines the start time for the first commit""" - - applicable_product_ids: Optional[List[str]] = None - """Will be passed down to the individual commits""" - - applicable_product_tags: Optional[List[str]] = None - """Will be passed down to the individual commits""" - - contract: Optional[RecurringCreditContract] = None - - description: Optional[str] = None - """Will be passed down to the individual commits""" - - ending_before: Optional[datetime] = None - """Determines when the contract will stop creating recurring commits. Optional""" - - hierarchy_configuration: Optional[CommitHierarchyConfiguration] = None - """Optional configuration for recurring credit hierarchy access control""" - - name: Optional[str] = None - """Displayed on invoices. Will be passed through to the individual commits""" - - netsuite_sales_order_id: Optional[str] = None - """Will be passed down to the individual commits""" - - proration: Optional[Literal["NONE", "FIRST", "LAST", "FIRST_AND_LAST"]] = None - """Determines whether the first and last commit will be prorated. - - If not provided, the default is FIRST_AND_LAST (i.e. prorate both the first and - last commits). - """ - - recurrence_frequency: Optional[Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"]] = None - """The frequency at which the recurring commits will be created. - - If not provided: - The commits will be created on the usage invoice frequency. - If provided: - The period defined in the duration will correspond to this - frequency. - Commits will be created aligned with the recurring commit's - starting_at rather than the usage invoice dates. - """ - - rollover_fraction: Optional[float] = None - """Will be passed down to the individual commits. - - This controls how much of an individual unexpired commit will roll over upon - contract transition. Must be between 0 and 1. - """ - - specifiers: Optional[List[CommitSpecifier]] = None - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. - """ - - subscription_config: Optional[RecurringCommitSubscriptionConfig] = None - """Attach a subscription to the recurring commit/credit.""" - - -class ResellerRoyaltySegment(BaseModel): - fraction: float - - netsuite_reseller_id: str - - reseller_type: Literal["AWS", "AWS_PRO_SERVICE", "GCP", "GCP_PRO_SERVICE"] - - starting_at: datetime - - applicable_product_ids: Optional[List[str]] = None - - applicable_product_tags: Optional[List[str]] = None - - aws_account_number: Optional[str] = None - - aws_offer_id: Optional[str] = None - - aws_payer_reference_id: Optional[str] = None - - ending_before: Optional[datetime] = None - - gcp_account_id: Optional[str] = None - - gcp_offer_id: Optional[str] = None - - reseller_contract_value: Optional[float] = None - - -class ResellerRoyalty(BaseModel): - reseller_type: Literal["AWS", "AWS_PRO_SERVICE", "GCP", "GCP_PRO_SERVICE"] - - segments: List[ResellerRoyaltySegment] - - -class ContractV2(BaseModel): - id: str - - commits: List[Commit] - - created_at: datetime - - created_by: str - - customer_id: str - - overrides: List[Override] - - scheduled_charges: List[ScheduledCharge] - - starting_at: datetime - - transitions: List[Transition] - - usage_filter: List[UsageFilter] - - usage_statement_schedule: UsageStatementSchedule - - archived_at: Optional[datetime] = None - - credits: Optional[List[Credit]] = None - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - customer_billing_provider_configuration: Optional[CustomerBillingProviderConfiguration] = None - """This field's availability is dependent on your client's configuration.""" - - discounts: Optional[List[Discount]] = None - """This field's availability is dependent on your client's configuration.""" - - ending_before: Optional[datetime] = None - - has_more: Optional[HasMore] = None - """Indicates whether there are more items than the limit for this endpoint. - - Use the respective list endpoints to get the full lists. - """ - - hierarchy_configuration: Optional[HierarchyConfiguration] = None - """ - Either a **parent** configuration with a list of children or a **child** - configuration with a single parent. - """ - - multiplier_override_prioritization: Optional[Literal["LOWEST_MULTIPLIER", "EXPLICIT"]] = None - """ - Defaults to LOWEST_MULTIPLIER, which applies the greatest discount to list - prices automatically. EXPLICIT prioritization requires specifying priorities for - each multiplier; the one with the lowest priority value will be prioritized - first. - """ - - name: Optional[str] = None - - net_payment_terms_days: Optional[float] = None - - netsuite_sales_order_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - prepaid_balance_threshold_configuration: Optional[PrepaidBalanceThresholdConfigurationV2] = None - - priority: Optional[float] = None - """Priority of the contract.""" - - professional_services: Optional[List[ProService]] = None - """This field's availability is dependent on your client's configuration.""" - - rate_card_id: Optional[str] = None - - recurring_commits: Optional[List[RecurringCommit]] = None - - recurring_credits: Optional[List[RecurringCredit]] = None - - reseller_royalties: Optional[List[ResellerRoyalty]] = None - """This field's availability is dependent on your client's configuration.""" - - salesforce_opportunity_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - scheduled_charges_on_usage_invoices: Optional[Literal["ALL"]] = None - """ - Determines which scheduled and commit charges to consolidate onto the Contract's - usage invoice. The charge's `timestamp` must match the usage invoice's - `ending_before` date for consolidation to occur. This field cannot be modified - after a Contract has been created. If this field is omitted, charges will appear - on a separate invoice from usage charges. - """ - - spend_threshold_configuration: Optional[SpendThresholdConfigurationV2] = None - - subscriptions: Optional[List[Subscription]] = None - """List of subscriptions on the contract.""" - - total_contract_value: Optional[float] = None - - uniqueness_key: Optional[str] = None - """Optional uniqueness key to prevent duplicate contract creations.""" diff --git a/src/metronome/types/shared/contract_without_amendments.py b/src/metronome/types/shared/contract_without_amendments.py deleted file mode 100644 index 5a92c019f..000000000 --- a/src/metronome/types/shared/contract_without_amendments.py +++ /dev/null @@ -1,393 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime -from typing_extensions import Literal - -from .commit import Commit -from .credit import Credit -from .discount import Discount -from .override import Override -from ..._models import BaseModel -from .pro_service import ProService -from .commit_specifier import CommitSpecifier -from .scheduled_charge import ScheduledCharge -from .base_usage_filter import BaseUsageFilter -from .hierarchy_configuration import HierarchyConfiguration -from .spend_threshold_configuration import SpendThresholdConfiguration -from .commit_hierarchy_configuration import CommitHierarchyConfiguration -from .recurring_commit_subscription_config import RecurringCommitSubscriptionConfig -from .prepaid_balance_threshold_configuration import PrepaidBalanceThresholdConfiguration - -__all__ = [ - "ContractWithoutAmendments", - "Transition", - "UsageStatementSchedule", - "RecurringCommit", - "RecurringCommitAccessAmount", - "RecurringCommitCommitDuration", - "RecurringCommitProduct", - "RecurringCommitContract", - "RecurringCommitInvoiceAmount", - "RecurringCredit", - "RecurringCreditAccessAmount", - "RecurringCreditCommitDuration", - "RecurringCreditProduct", - "RecurringCreditContract", - "ResellerRoyalty", - "UsageFilter", - "UsageFilterUpdate", -] - - -class Transition(BaseModel): - from_contract_id: str - - to_contract_id: str - - type: Literal["SUPERSEDE", "RENEWAL"] - - -class UsageStatementSchedule(BaseModel): - billing_anchor_date: datetime - """Contract usage statements follow a selected cadence based on this date.""" - - frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"] - - -class RecurringCommitAccessAmount(BaseModel): - """The amount of commit to grant.""" - - credit_type_id: str - - unit_price: float - - quantity: Optional[float] = None - - -class RecurringCommitCommitDuration(BaseModel): - """The amount of time the created commits will be valid for""" - - value: float - - unit: Optional[Literal["PERIODS"]] = None - - -class RecurringCommitProduct(BaseModel): - id: str - - name: str - - -class RecurringCommitContract(BaseModel): - id: str - - -class RecurringCommitInvoiceAmount(BaseModel): - """The amount the customer should be billed for the commit. Not required.""" - - credit_type_id: str - - quantity: float - - unit_price: float - - -class RecurringCommit(BaseModel): - id: str - - access_amount: RecurringCommitAccessAmount - """The amount of commit to grant.""" - - commit_duration: RecurringCommitCommitDuration - """The amount of time the created commits will be valid for""" - - priority: float - """Will be passed down to the individual commits""" - - product: RecurringCommitProduct - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - """Whether the created commits will use the commit rate or list rate""" - - starting_at: datetime - """Determines the start time for the first commit""" - - applicable_product_ids: Optional[List[str]] = None - """Will be passed down to the individual commits""" - - applicable_product_tags: Optional[List[str]] = None - """Will be passed down to the individual commits""" - - contract: Optional[RecurringCommitContract] = None - - description: Optional[str] = None - """Will be passed down to the individual commits""" - - ending_before: Optional[datetime] = None - """Determines when the contract will stop creating recurring commits. Optional""" - - hierarchy_configuration: Optional[CommitHierarchyConfiguration] = None - """Optional configuration for recurring commit/credit hierarchy access control""" - - invoice_amount: Optional[RecurringCommitInvoiceAmount] = None - """The amount the customer should be billed for the commit. Not required.""" - - name: Optional[str] = None - """Displayed on invoices. Will be passed through to the individual commits""" - - netsuite_sales_order_id: Optional[str] = None - """Will be passed down to the individual commits""" - - proration: Optional[Literal["NONE", "FIRST", "LAST", "FIRST_AND_LAST"]] = None - """Determines whether the first and last commit will be prorated. - - If not provided, the default is FIRST_AND_LAST (i.e. prorate both the first and - last commits). - """ - - recurrence_frequency: Optional[Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"]] = None - """The frequency at which the recurring commits will be created. - - If not provided: - The commits will be created on the usage invoice frequency. - If provided: - The period defined in the duration will correspond to this - frequency. - Commits will be created aligned with the recurring commit's - starting_at rather than the usage invoice dates. - """ - - rollover_fraction: Optional[float] = None - """Will be passed down to the individual commits. - - This controls how much of an individual unexpired commit will roll over upon - contract transition. Must be between 0 and 1. - """ - - specifiers: Optional[List[CommitSpecifier]] = None - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. - """ - - subscription_config: Optional[RecurringCommitSubscriptionConfig] = None - """Attach a subscription to the recurring commit/credit.""" - - -class RecurringCreditAccessAmount(BaseModel): - """The amount of commit to grant.""" - - credit_type_id: str - - unit_price: float - - quantity: Optional[float] = None - - -class RecurringCreditCommitDuration(BaseModel): - """The amount of time the created commits will be valid for""" - - value: float - - unit: Optional[Literal["PERIODS"]] = None - - -class RecurringCreditProduct(BaseModel): - id: str - - name: str - - -class RecurringCreditContract(BaseModel): - id: str - - -class RecurringCredit(BaseModel): - id: str - - access_amount: RecurringCreditAccessAmount - """The amount of commit to grant.""" - - commit_duration: RecurringCreditCommitDuration - """The amount of time the created commits will be valid for""" - - priority: float - """Will be passed down to the individual commits""" - - product: RecurringCreditProduct - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - """Whether the created commits will use the commit rate or list rate""" - - starting_at: datetime - """Determines the start time for the first commit""" - - applicable_product_ids: Optional[List[str]] = None - """Will be passed down to the individual commits""" - - applicable_product_tags: Optional[List[str]] = None - """Will be passed down to the individual commits""" - - contract: Optional[RecurringCreditContract] = None - - description: Optional[str] = None - """Will be passed down to the individual commits""" - - ending_before: Optional[datetime] = None - """Determines when the contract will stop creating recurring commits. Optional""" - - hierarchy_configuration: Optional[CommitHierarchyConfiguration] = None - """Optional configuration for recurring commit/credit hierarchy access control""" - - name: Optional[str] = None - """Displayed on invoices. Will be passed through to the individual commits""" - - netsuite_sales_order_id: Optional[str] = None - """Will be passed down to the individual commits""" - - proration: Optional[Literal["NONE", "FIRST", "LAST", "FIRST_AND_LAST"]] = None - """Determines whether the first and last commit will be prorated. - - If not provided, the default is FIRST_AND_LAST (i.e. prorate both the first and - last commits). - """ - - recurrence_frequency: Optional[Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"]] = None - """The frequency at which the recurring commits will be created. - - If not provided: - The commits will be created on the usage invoice frequency. - If provided: - The period defined in the duration will correspond to this - frequency. - Commits will be created aligned with the recurring commit's - starting_at rather than the usage invoice dates. - """ - - rollover_fraction: Optional[float] = None - """Will be passed down to the individual commits. - - This controls how much of an individual unexpired commit will roll over upon - contract transition. Must be between 0 and 1. - """ - - specifiers: Optional[List[CommitSpecifier]] = None - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. - """ - - subscription_config: Optional[RecurringCommitSubscriptionConfig] = None - """Attach a subscription to the recurring commit/credit.""" - - -class ResellerRoyalty(BaseModel): - fraction: float - - netsuite_reseller_id: str - - reseller_type: Literal["AWS", "AWS_PRO_SERVICE", "GCP", "GCP_PRO_SERVICE"] - - starting_at: datetime - - applicable_product_ids: Optional[List[str]] = None - - applicable_product_tags: Optional[List[str]] = None - - aws_account_number: Optional[str] = None - - aws_offer_id: Optional[str] = None - - aws_payer_reference_id: Optional[str] = None - - ending_before: Optional[datetime] = None - - gcp_account_id: Optional[str] = None - - gcp_offer_id: Optional[str] = None - - reseller_contract_value: Optional[float] = None - - -class UsageFilterUpdate(BaseModel): - group_key: str - - group_values: List[str] - - starting_at: datetime - - -class UsageFilter(BaseModel): - current: Optional[BaseUsageFilter] = None - - initial: BaseUsageFilter - - updates: List[UsageFilterUpdate] - - -class ContractWithoutAmendments(BaseModel): - commits: List[Commit] - - created_at: datetime - - created_by: str - - overrides: List[Override] - - scheduled_charges: List[ScheduledCharge] - - starting_at: datetime - - transitions: List[Transition] - - usage_statement_schedule: UsageStatementSchedule - - credits: Optional[List[Credit]] = None - - discounts: Optional[List[Discount]] = None - """This field's availability is dependent on your client's""" - - ending_before: Optional[datetime] = None - - hierarchy_configuration: Optional[HierarchyConfiguration] = None - """ - Either a **parent** configuration with a list of children or a **child** - configuration with a single parent. - """ - - name: Optional[str] = None - - net_payment_terms_days: Optional[float] = None - - netsuite_sales_order_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - prepaid_balance_threshold_configuration: Optional[PrepaidBalanceThresholdConfiguration] = None - - professional_services: Optional[List[ProService]] = None - """This field's availability is dependent on your client's configuration.""" - - rate_card_id: Optional[str] = None - - recurring_commits: Optional[List[RecurringCommit]] = None - - recurring_credits: Optional[List[RecurringCredit]] = None - - reseller_royalties: Optional[List[ResellerRoyalty]] = None - """This field's availability is dependent on your client's configuration.""" - - salesforce_opportunity_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - scheduled_charges_on_usage_invoices: Optional[Literal["ALL"]] = None - """ - Determines which scheduled and commit charges to consolidate onto the Contract's - usage invoice. The charge's `timestamp` must match the usage invoice's - `ending_before` date for consolidation to occur. This field cannot be modified - after a Contract has been created. If this field is omitted, charges will appear - on a separate invoice from usage charges. - """ - - spend_threshold_configuration: Optional[SpendThresholdConfiguration] = None - - total_contract_value: Optional[float] = None - """This field's availability is dependent on your client's configuration.""" - - usage_filter: Optional[UsageFilter] = None diff --git a/src/metronome/types/shared/credit.py b/src/metronome/types/shared/credit.py deleted file mode 100644 index a70a92b2a..000000000 --- a/src/metronome/types/shared/credit.py +++ /dev/null @@ -1,235 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Union, Optional -from datetime import datetime -from typing_extensions import Literal, TypeAlias - -from ..._models import BaseModel -from .commit_specifier import CommitSpecifier -from .schedule_duration import ScheduleDuration -from .commit_hierarchy_configuration import CommitHierarchyConfiguration - -__all__ = [ - "Credit", - "Product", - "Contract", - "Ledger", - "LedgerCreditSegmentStartLedgerEntry", - "LedgerCreditAutomatedInvoiceDeductionLedgerEntry", - "LedgerCreditExpirationLedgerEntry", - "LedgerCreditCanceledLedgerEntry", - "LedgerCreditCreditedLedgerEntry", - "LedgerCreditManualLedgerEntry", - "LedgerCreditSeatBasedAdjustmentLedgerEntry", - "SubscriptionConfig", - "SubscriptionConfigApplySeatIncreaseConfig", -] - - -class Product(BaseModel): - id: str - - name: str - - -class Contract(BaseModel): - id: str - - -class LedgerCreditSegmentStartLedgerEntry(BaseModel): - amount: float - - segment_id: str - - timestamp: datetime - - type: Literal["CREDIT_SEGMENT_START"] - - -class LedgerCreditAutomatedInvoiceDeductionLedgerEntry(BaseModel): - amount: float - - invoice_id: str - - segment_id: str - - timestamp: datetime - - type: Literal["CREDIT_AUTOMATED_INVOICE_DEDUCTION"] - - contract_id: Optional[str] = None - - -class LedgerCreditExpirationLedgerEntry(BaseModel): - amount: float - - segment_id: str - - timestamp: datetime - - type: Literal["CREDIT_EXPIRATION"] - - -class LedgerCreditCanceledLedgerEntry(BaseModel): - amount: float - - invoice_id: str - - segment_id: str - - timestamp: datetime - - type: Literal["CREDIT_CANCELED"] - - contract_id: Optional[str] = None - - -class LedgerCreditCreditedLedgerEntry(BaseModel): - amount: float - - invoice_id: str - - segment_id: str - - timestamp: datetime - - type: Literal["CREDIT_CREDITED"] - - contract_id: Optional[str] = None - - -class LedgerCreditManualLedgerEntry(BaseModel): - amount: float - - reason: str - - timestamp: datetime - - type: Literal["CREDIT_MANUAL"] - - -class LedgerCreditSeatBasedAdjustmentLedgerEntry(BaseModel): - amount: float - - segment_id: str - - timestamp: datetime - - type: Literal["CREDIT_SEAT_BASED_ADJUSTMENT"] - - -Ledger: TypeAlias = Union[ - LedgerCreditSegmentStartLedgerEntry, - LedgerCreditAutomatedInvoiceDeductionLedgerEntry, - LedgerCreditExpirationLedgerEntry, - LedgerCreditCanceledLedgerEntry, - LedgerCreditCreditedLedgerEntry, - LedgerCreditManualLedgerEntry, - LedgerCreditSeatBasedAdjustmentLedgerEntry, -] - - -class SubscriptionConfigApplySeatIncreaseConfig(BaseModel): - is_prorated: bool - """Indicates whether a mid-period seat increase should be prorated.""" - - -class SubscriptionConfig(BaseModel): - """ - The subscription configuration for this credit, if it was generated from a recurring credit with a subscription attached. - """ - - allocation: Optional[Literal["INDIVIDUAL", "POOLED"]] = None - - apply_seat_increase_config: Optional[SubscriptionConfigApplySeatIncreaseConfig] = None - - subscription_id: Optional[str] = None - - -class Credit(BaseModel): - id: str - - product: Product - - type: Literal["CREDIT"] - - access_schedule: Optional[ScheduleDuration] = None - """The schedule that the customer will gain access to the credits.""" - - applicable_contract_ids: Optional[List[str]] = None - - applicable_product_ids: Optional[List[str]] = None - - applicable_product_tags: Optional[List[str]] = None - - balance: Optional[float] = None - """The current balance of the credit or commit. - - This balance reflects the amount of credit or commit that the customer has - access to use at this moment - thus, expired and upcoming credit or commit - segments contribute 0 to the balance. The balance will match the sum of all - ledger entries with the exception of the case where the sum of negative manual - ledger entries exceeds the positive amount remaining on the credit or commit - - in that case, the balance will be 0. All manual ledger entries associated with - active credit or commit segments are included in the balance, including - future-dated manual ledger entries. - """ - - contract: Optional[Contract] = None - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: Optional[str] = None - - hierarchy_configuration: Optional[CommitHierarchyConfiguration] = None - """Optional configuration for credit hierarchy access control""" - - ledger: Optional[List[Ledger]] = None - """A list of ordered events that impact the balance of a credit. - - For example, an invoice deduction or an expiration. - """ - - name: Optional[str] = None - - netsuite_sales_order_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - priority: Optional[float] = None - """ - If multiple credits or commits are applicable, the one with the lower priority - will apply first. - """ - - rate_type: Optional[Literal["COMMIT_RATE", "LIST_RATE"]] = None - - recurring_credit_id: Optional[str] = None - """ - The ID of the recurring credit that this credit was generated from, if - applicable. - """ - - salesforce_opportunity_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - specifiers: Optional[List[CommitSpecifier]] = None - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. - """ - - subscription_config: Optional[SubscriptionConfig] = None - """ - The subscription configuration for this credit, if it was generated from a - recurring credit with a subscription attached. - """ - - uniqueness_key: Optional[str] = None - """Prevents the creation of duplicates. - - If a request to create a commit or credit is made with a uniqueness key that was - previously used to create a commit or credit, a new record will not be created - and the request will fail with a 409 error. - """ diff --git a/src/metronome/types/shared/credit_type_data.py b/src/metronome/types/shared/credit_type_data.py deleted file mode 100644 index d53783c1a..000000000 --- a/src/metronome/types/shared/credit_type_data.py +++ /dev/null @@ -1,11 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel - -__all__ = ["CreditTypeData"] - - -class CreditTypeData(BaseModel): - id: str - - name: str diff --git a/src/metronome/types/shared/discount.py b/src/metronome/types/shared/discount.py deleted file mode 100644 index 05c845bc1..000000000 --- a/src/metronome/types/shared/discount.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Optional - -from ..._models import BaseModel -from .schedule_point_in_time import SchedulePointInTime - -__all__ = ["Discount", "Product"] - - -class Product(BaseModel): - id: str - - name: str - - -class Discount(BaseModel): - id: str - - product: Product - - schedule: SchedulePointInTime - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - name: Optional[str] = None - - netsuite_sales_order_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" diff --git a/src/metronome/types/shared/event_type_filter.py b/src/metronome/types/shared/event_type_filter.py deleted file mode 100644 index 10e5b8a8e..000000000 --- a/src/metronome/types/shared/event_type_filter.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional - -from ..._models import BaseModel - -__all__ = ["EventTypeFilter"] - - -class EventTypeFilter(BaseModel): - """An optional filtering rule to match the 'event_type' property of an event.""" - - in_values: Optional[List[str]] = None - """A list of event types that are explicitly included in the billable metric. - - If specified, only events of these types will match the billable metric. Must be - non-empty if present. - """ - - not_in_values: Optional[List[str]] = None - """A list of event types that are explicitly excluded from the billable metric. - - If specified, events of these types will not match the billable metric. Must be - non-empty if present. - """ diff --git a/src/metronome/types/shared/hierarchy_configuration.py b/src/metronome/types/shared/hierarchy_configuration.py deleted file mode 100644 index f7df3642d..000000000 --- a/src/metronome/types/shared/hierarchy_configuration.py +++ /dev/null @@ -1,77 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Union, Optional -from typing_extensions import Literal, TypeAlias - -from ..._models import BaseModel - -__all__ = [ - "HierarchyConfiguration", - "ParentHierarchyConfiguration", - "ParentHierarchyConfigurationChild", - "ParentHierarchyConfigurationParentBehavior", - "ChildHierarchyConfiguration", - "ChildHierarchyConfigurationParent", -] - - -class ParentHierarchyConfigurationChild(BaseModel): - contract_id: str - - customer_id: str - - -class ParentHierarchyConfigurationParentBehavior(BaseModel): - invoice_consolidation_type: Optional[Literal["CONCATENATE", "NONE"]] = None - """ - Indicates the desired behavior of consolidated invoices generated by the parent - in a customer hierarchy - - **CONCATENATE**: Statements on the invoices of child customers will be appended - to the consolidated invoice - - **NONE**: Do not generate consolidated invoices - """ - - -class ParentHierarchyConfiguration(BaseModel): - children: List[ParentHierarchyConfigurationChild] - """List of contracts that belong to this parent.""" - - parent_behavior: Optional[ParentHierarchyConfigurationParentBehavior] = None - - -class ChildHierarchyConfigurationParent(BaseModel): - """The single parent contract/customer for this child.""" - - contract_id: str - - customer_id: str - - -class ChildHierarchyConfiguration(BaseModel): - parent: ChildHierarchyConfigurationParent - """The single parent contract/customer for this child.""" - - payer: Optional[Literal["SELF", "PARENT"]] = None - """Indicates which customer should pay for the child's invoice charges - - **SELF**: The child pays for its own invoice charges - - **PARENT**: The parent pays for the child's invoice charges - """ - - usage_statement_behavior: Optional[Literal["CONSOLIDATE", "SEPARATE"]] = None - """ - Indicates the behavior of the child's invoice statements on the parent's - invoices. - - **CONSOLIDATE**: Child's invoice statements will be added to parent's - consolidated invoices - - **SEPARATE**: Child's invoice statements will appear not appear on parent's - consolidated invoices - """ - - -HierarchyConfiguration: TypeAlias = Union[ParentHierarchyConfiguration, ChildHierarchyConfiguration] diff --git a/src/metronome/types/shared/id.py b/src/metronome/types/shared/id.py deleted file mode 100644 index 76e18fc3d..000000000 --- a/src/metronome/types/shared/id.py +++ /dev/null @@ -1,9 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel - -__all__ = ["ID"] - - -class ID(BaseModel): - id: str diff --git a/src/metronome/types/shared/override.py b/src/metronome/types/shared/override.py deleted file mode 100644 index e5ea19908..000000000 --- a/src/metronome/types/shared/override.py +++ /dev/null @@ -1,96 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from datetime import datetime -from typing_extensions import Literal - -from .tier import Tier -from ..._models import BaseModel -from .override_tier import OverrideTier -from .overwrite_rate import OverwriteRate -from .credit_type_data import CreditTypeData - -__all__ = ["Override", "OverrideSpecifier", "Product"] - - -class OverrideSpecifier(BaseModel): - billing_frequency: Optional[Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"]] = None - - commit_ids: Optional[List[str]] = None - - presentation_group_values: Optional[Dict[str, Optional[str]]] = None - - pricing_group_values: Optional[Dict[str, str]] = None - - product_id: Optional[str] = None - - product_tags: Optional[List[str]] = None - - recurring_commit_ids: Optional[List[str]] = None - - recurring_credit_ids: Optional[List[str]] = None - - -class Product(BaseModel): - id: str - - name: str - - -class Override(BaseModel): - id: str - - starting_at: datetime - - applicable_product_tags: Optional[List[str]] = None - - credit_type: Optional[CreditTypeData] = None - - ending_before: Optional[datetime] = None - - entitled: Optional[bool] = None - - is_commit_specific: Optional[bool] = None - - is_prorated: Optional[bool] = None - """Default proration configuration. - - Only valid for SUBSCRIPTION rate_type. Must be set to true. - """ - - multiplier: Optional[float] = None - - override_specifiers: Optional[List[OverrideSpecifier]] = None - - override_tiers: Optional[List[OverrideTier]] = None - - overwrite_rate: Optional[OverwriteRate] = None - - price: Optional[float] = None - """Default price. - - For FLAT rate_type, this must be >=0. For PERCENTAGE rate_type, this is a - decimal fraction, e.g. use 0.1 for 10%; this must be >=0 and <=1. - """ - - priority: Optional[float] = None - - product: Optional[Product] = None - - quantity: Optional[float] = None - """Default quantity. For SUBSCRIPTION rate_type, this must be >=0.""" - - rate_type: Optional[Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "TIERED", "TIERED_PERCENTAGE", "CUSTOM"]] = None - - target: Optional[Literal["COMMIT_RATE", "LIST_RATE"]] = None - - tiers: Optional[List[Tier]] = None - """Only set for TIERED rate_type.""" - - type: Optional[Literal["OVERWRITE", "MULTIPLIER", "TIERED"]] = None - - value: Optional[Dict[str, object]] = None - """Only set for CUSTOM rate_type. - - This field is interpreted by custom rate processors. - """ diff --git a/src/metronome/types/shared/override_tier.py b/src/metronome/types/shared/override_tier.py deleted file mode 100644 index 7630fedac..000000000 --- a/src/metronome/types/shared/override_tier.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ..._models import BaseModel - -__all__ = ["OverrideTier"] - - -class OverrideTier(BaseModel): - multiplier: float - - size: Optional[float] = None diff --git a/src/metronome/types/shared/overwrite_rate.py b/src/metronome/types/shared/overwrite_rate.py deleted file mode 100644 index 19daf8f70..000000000 --- a/src/metronome/types/shared/overwrite_rate.py +++ /dev/null @@ -1,41 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from typing_extensions import Literal - -from .tier import Tier -from ..._models import BaseModel -from .credit_type_data import CreditTypeData - -__all__ = ["OverwriteRate"] - - -class OverwriteRate(BaseModel): - rate_type: Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "TIERED", "TIERED_PERCENTAGE", "CUSTOM"] - - credit_type: Optional[CreditTypeData] = None - - custom_rate: Optional[Dict[str, object]] = None - """Only set for CUSTOM rate_type. - - This field is interpreted by custom rate processors. - """ - - is_prorated: Optional[bool] = None - """Default proration configuration. - - Only valid for SUBSCRIPTION rate_type. Must be set to true. - """ - - price: Optional[float] = None - """Default price. - - For FLAT rate_type, this must be >=0. For PERCENTAGE rate_type, this is a - decimal fraction, e.g. use 0.1 for 10%; this must be >=0 and <=1. - """ - - quantity: Optional[float] = None - """Default quantity. For SUBSCRIPTION rate_type, this must be >=0.""" - - tiers: Optional[List[Tier]] = None - """Only set for TIERED rate_type.""" diff --git a/src/metronome/types/shared/payment_gate_config.py b/src/metronome/types/shared/payment_gate_config.py deleted file mode 100644 index 543d9e4d2..000000000 --- a/src/metronome/types/shared/payment_gate_config.py +++ /dev/null @@ -1,61 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["PaymentGateConfig", "PrecalculatedTaxConfig", "StripeConfig"] - - -class PrecalculatedTaxConfig(BaseModel): - """Only applicable if using PRECALCULATED as your tax type.""" - - tax_amount: float - """Amount of tax to be applied. - - This should be in the same currency and denomination as the commit's invoice - schedule - """ - - tax_name: Optional[str] = None - """Name of the tax to be applied. - - This may be used in an invoice line item description. - """ - - -class StripeConfig(BaseModel): - """Only applicable if using STRIPE as your payment gate type.""" - - payment_type: Literal["INVOICE", "PAYMENT_INTENT"] - """If left blank, will default to INVOICE""" - - invoice_metadata: Optional[Dict[str, str]] = None - """Metadata to be added to the Stripe invoice. - - Only applicable if using INVOICE as your payment type. - """ - - -class PaymentGateConfig(BaseModel): - payment_gate_type: Literal["NONE", "STRIPE", "EXTERNAL"] - """Gate access to the commit balance based on successful collection of payment. - - Select STRIPE for Metronome to facilitate payment via Stripe. Select EXTERNAL to - facilitate payment using your own payment integration. Select NONE if you do not - wish to payment gate the commit balance. - """ - - precalculated_tax_config: Optional[PrecalculatedTaxConfig] = None - """Only applicable if using PRECALCULATED as your tax type.""" - - stripe_config: Optional[StripeConfig] = None - """Only applicable if using STRIPE as your payment gate type.""" - - tax_type: Optional[Literal["NONE", "STRIPE", "ANROK", "PRECALCULATED"]] = None - """Stripe tax is only supported for Stripe payment gateway. - - Select NONE if you do not wish Metronome to calculate tax on your behalf. - Leaving this field blank will default to NONE. - """ diff --git a/src/metronome/types/shared/payment_gate_config_v2.py b/src/metronome/types/shared/payment_gate_config_v2.py deleted file mode 100644 index ef2ac74e3..000000000 --- a/src/metronome/types/shared/payment_gate_config_v2.py +++ /dev/null @@ -1,61 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["PaymentGateConfigV2", "PrecalculatedTaxConfig", "StripeConfig"] - - -class PrecalculatedTaxConfig(BaseModel): - """Only applicable if using PRECALCULATED as your tax type.""" - - tax_amount: float - """Amount of tax to be applied. - - This should be in the same currency and denomination as the commit's invoice - schedule - """ - - tax_name: Optional[str] = None - """Name of the tax to be applied. - - This may be used in an invoice line item description. - """ - - -class StripeConfig(BaseModel): - """Only applicable if using STRIPE as your payment gateway type.""" - - payment_type: Literal["INVOICE", "PAYMENT_INTENT"] - """If left blank, will default to INVOICE""" - - invoice_metadata: Optional[Dict[str, str]] = None - """Metadata to be added to the Stripe invoice. - - Only applicable if using INVOICE as your payment type. - """ - - -class PaymentGateConfigV2(BaseModel): - payment_gate_type: Literal["NONE", "STRIPE", "EXTERNAL"] - """Gate access to the commit balance based on successful collection of payment. - - Select STRIPE for Metronome to facilitate payment via Stripe. Select EXTERNAL to - facilitate payment using your own payment integration. Select NONE if you do not - wish to payment gate the commit balance. - """ - - precalculated_tax_config: Optional[PrecalculatedTaxConfig] = None - """Only applicable if using PRECALCULATED as your tax type.""" - - stripe_config: Optional[StripeConfig] = None - """Only applicable if using STRIPE as your payment gateway type.""" - - tax_type: Optional[Literal["NONE", "STRIPE", "ANROK", "PRECALCULATED"]] = None - """Stripe tax is only supported for Stripe payment gateway. - - Select NONE if you do not wish Metronome to calculate tax on your behalf. - Leaving this field blank will default to NONE. - """ diff --git a/src/metronome/types/shared/prepaid_balance_threshold_configuration.py b/src/metronome/types/shared/prepaid_balance_threshold_configuration.py deleted file mode 100644 index c8b0fdf80..000000000 --- a/src/metronome/types/shared/prepaid_balance_threshold_configuration.py +++ /dev/null @@ -1,63 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional - -from ..._models import BaseModel -from .payment_gate_config import PaymentGateConfig -from .base_threshold_commit import BaseThresholdCommit -from .commit_specifier_input import CommitSpecifierInput - -__all__ = ["PrepaidBalanceThresholdConfiguration", "Commit"] - - -class Commit(BaseThresholdCommit): - applicable_product_ids: Optional[List[str]] = None - """Which products the threshold commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - applicable_product_tags: Optional[List[str]] = None - """Which tags the threshold commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - specifiers: Optional[List[CommitSpecifierInput]] = None - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - """ - - -class PrepaidBalanceThresholdConfiguration(BaseModel): - commit: Commit - - is_enabled: bool - """ - When set to false, the contract will not be evaluated against the - threshold_amount. Toggling to true will result an immediate evaluation, - regardless of prior state. - """ - - payment_gate_config: PaymentGateConfig - - recharge_to_amount: float - """Specify the amount the balance should be recharged to.""" - - threshold_amount: float - """Specify the threshold amount for the contract. - - Each time the contract's prepaid balance lowers to this amount, a threshold - charge will be initiated. - """ - - custom_credit_type_id: Optional[str] = None - """ - If provided, the threshold, recharge-to amount, and the resulting threshold - commit amount will be in terms of this credit type instead of the fiat currency. - """ diff --git a/src/metronome/types/shared/prepaid_balance_threshold_configuration_v2.py b/src/metronome/types/shared/prepaid_balance_threshold_configuration_v2.py deleted file mode 100644 index 932e45fec..000000000 --- a/src/metronome/types/shared/prepaid_balance_threshold_configuration_v2.py +++ /dev/null @@ -1,65 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional - -from ..._models import BaseModel -from .commit_specifier_input import CommitSpecifierInput -from .payment_gate_config_v2 import PaymentGateConfigV2 -from .update_base_threshold_commit import UpdateBaseThresholdCommit - -__all__ = ["PrepaidBalanceThresholdConfigurationV2", "Commit"] - - -class Commit(UpdateBaseThresholdCommit): - applicable_product_ids: Optional[List[str]] = None - """Which products the threshold commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - applicable_product_tags: Optional[List[str]] = None - """Which tags the threshold commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - specifiers: Optional[List[CommitSpecifierInput]] = None - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - Instead, to target usage by product or product tag, pass those values in the - body of `specifiers`. - """ - - -class PrepaidBalanceThresholdConfigurationV2(BaseModel): - commit: Commit - - is_enabled: bool - """ - When set to false, the contract will not be evaluated against the - threshold_amount. Toggling to true will result an immediate evaluation, - regardless of prior state. - """ - - payment_gate_config: PaymentGateConfigV2 - - recharge_to_amount: float - """Specify the amount the balance should be recharged to.""" - - threshold_amount: float - """Specify the threshold amount for the contract. - - Each time the contract's balance lowers to this amount, a threshold charge will - be initiated. - """ - - custom_credit_type_id: Optional[str] = None - """ - If provided, the threshold, recharge-to amount, and the resulting threshold - commit amount will be in terms of this credit type instead of the fiat currency. - """ diff --git a/src/metronome/types/shared/pro_service.py b/src/metronome/types/shared/pro_service.py deleted file mode 100644 index 0c28cd63c..000000000 --- a/src/metronome/types/shared/pro_service.py +++ /dev/null @@ -1,36 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Optional - -from ..._models import BaseModel - -__all__ = ["ProService"] - - -class ProService(BaseModel): - id: str - - max_amount: float - """Maximum amount for the term.""" - - product_id: str - - quantity: float - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount. - """ - - unit_price: float - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified. - """ - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: Optional[str] = None - - netsuite_sales_order_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" diff --git a/src/metronome/types/shared/property_filter.py b/src/metronome/types/shared/property_filter.py deleted file mode 100644 index 5127562f8..000000000 --- a/src/metronome/types/shared/property_filter.py +++ /dev/null @@ -1,36 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional - -from ..._models import BaseModel - -__all__ = ["PropertyFilter"] - - -class PropertyFilter(BaseModel): - name: str - """The name of the event property.""" - - exists: Optional[bool] = None - """Determines whether the property must exist in the event. - - If true, only events with this property will pass the filter. If false, only - events without this property will pass the filter. If null or omitted, the - existence of the property is optional. - """ - - in_values: Optional[List[str]] = None - """Specifies the allowed values for the property to match an event. - - An event will pass the filter only if its property value is included in this - list. If undefined, all property values will pass the filter. Must be non-empty - if present. - """ - - not_in_values: Optional[List[str]] = None - """Specifies the values that prevent an event from matching the filter. - - An event will not pass the filter if its property value is included in this - list. If null or empty, all property values will pass the filter. Must be - non-empty if present. - """ diff --git a/src/metronome/types/shared/rate.py b/src/metronome/types/shared/rate.py deleted file mode 100644 index 54e2d869d..000000000 --- a/src/metronome/types/shared/rate.py +++ /dev/null @@ -1,47 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from typing_extensions import Literal - -from .tier import Tier -from ..._models import BaseModel -from .credit_type_data import CreditTypeData - -__all__ = ["Rate"] - - -class Rate(BaseModel): - rate_type: Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "CUSTOM", "TIERED", "TIERED_PERCENTAGE"] - - credit_type: Optional[CreditTypeData] = None - - custom_rate: Optional[Dict[str, object]] = None - """Only set for CUSTOM rate_type. - - This field is interpreted by custom rate processors. - """ - - is_prorated: Optional[bool] = None - """Default proration configuration. - - Only valid for SUBSCRIPTION rate_type. Must be set to true. - """ - - price: Optional[float] = None - """Default price. - - For FLAT rate_type, this must be >=0. For PERCENTAGE rate_type, this is a - decimal fraction, e.g. use 0.1 for 10%; this must be >=0 and <=1. - """ - - pricing_group_values: Optional[Dict[str, str]] = None - """ - if pricing groups are used, this will contain the values used to calculate the - price - """ - - quantity: Optional[float] = None - """Default quantity. For SUBSCRIPTION rate_type, this must be >=0.""" - - tiers: Optional[List[Tier]] = None - """Only set for TIERED rate_type.""" diff --git a/src/metronome/types/shared/recurring_commit_subscription_config.py b/src/metronome/types/shared/recurring_commit_subscription_config.py deleted file mode 100644 index e49350c88..000000000 --- a/src/metronome/types/shared/recurring_commit_subscription_config.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["RecurringCommitSubscriptionConfig", "ApplySeatIncreaseConfig"] - - -class ApplySeatIncreaseConfig(BaseModel): - is_prorated: bool - """Indicates whether a mid-period seat increase should be prorated.""" - - -class RecurringCommitSubscriptionConfig(BaseModel): - allocation: Literal["INDIVIDUAL", "POOLED"] - - apply_seat_increase_config: ApplySeatIncreaseConfig - - subscription_id: str diff --git a/src/metronome/types/shared/schedule_duration.py b/src/metronome/types/shared/schedule_duration.py deleted file mode 100644 index 5e79ee482..000000000 --- a/src/metronome/types/shared/schedule_duration.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime - -from ..._models import BaseModel -from .credit_type_data import CreditTypeData - -__all__ = ["ScheduleDuration", "ScheduleItem"] - - -class ScheduleItem(BaseModel): - id: str - - amount: float - - ending_before: datetime - - starting_at: datetime - - -class ScheduleDuration(BaseModel): - schedule_items: List[ScheduleItem] - - credit_type: Optional[CreditTypeData] = None diff --git a/src/metronome/types/shared/schedule_point_in_time.py b/src/metronome/types/shared/schedule_point_in_time.py deleted file mode 100644 index 8ebecb7ef..000000000 --- a/src/metronome/types/shared/schedule_point_in_time.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime - -from ..._models import BaseModel -from .credit_type_data import CreditTypeData - -__all__ = ["SchedulePointInTime", "ScheduleItem"] - - -class ScheduleItem(BaseModel): - id: str - - amount: float - - quantity: float - - timestamp: datetime - - unit_price: float - - invoice_id: Optional[str] = None - - -class SchedulePointInTime(BaseModel): - credit_type: Optional[CreditTypeData] = None - - do_not_invoice: Optional[bool] = None - """This field is only applicable to commit invoice schedules. - - If true, this schedule will not generate an invoice. - """ - - schedule_items: Optional[List[ScheduleItem]] = None diff --git a/src/metronome/types/shared/scheduled_charge.py b/src/metronome/types/shared/scheduled_charge.py deleted file mode 100644 index 523ec789c..000000000 --- a/src/metronome/types/shared/scheduled_charge.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Optional -from datetime import datetime - -from ..._models import BaseModel -from .schedule_point_in_time import SchedulePointInTime - -__all__ = ["ScheduledCharge", "Product"] - - -class Product(BaseModel): - id: str - - name: str - - -class ScheduledCharge(BaseModel): - id: str - - product: Product - - schedule: SchedulePointInTime - - archived_at: Optional[datetime] = None - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - name: Optional[str] = None - """displayed on invoices""" - - netsuite_sales_order_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" diff --git a/src/metronome/types/shared/spend_threshold_configuration.py b/src/metronome/types/shared/spend_threshold_configuration.py deleted file mode 100644 index 2d872e5c1..000000000 --- a/src/metronome/types/shared/spend_threshold_configuration.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel -from .payment_gate_config import PaymentGateConfig -from .base_threshold_commit import BaseThresholdCommit - -__all__ = ["SpendThresholdConfiguration"] - - -class SpendThresholdConfiguration(BaseModel): - commit: BaseThresholdCommit - - is_enabled: bool - """ - When set to false, the contract will not be evaluated against the - threshold_amount. Toggling to true will result an immediate evaluation, - regardless of prior state. - """ - - payment_gate_config: PaymentGateConfig - - threshold_amount: float - """Specify the threshold amount for the contract. - - Each time the contract's usage hits this amount, a threshold charge will be - initiated. - """ diff --git a/src/metronome/types/shared/spend_threshold_configuration_v2.py b/src/metronome/types/shared/spend_threshold_configuration_v2.py deleted file mode 100644 index 7d413036d..000000000 --- a/src/metronome/types/shared/spend_threshold_configuration_v2.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel -from .payment_gate_config_v2 import PaymentGateConfigV2 -from .update_base_threshold_commit import UpdateBaseThresholdCommit - -__all__ = ["SpendThresholdConfigurationV2"] - - -class SpendThresholdConfigurationV2(BaseModel): - commit: UpdateBaseThresholdCommit - - is_enabled: bool - """ - When set to false, the contract will not be evaluated against the - threshold_amount. Toggling to true will result an immediate evaluation, - regardless of prior state. - """ - - payment_gate_config: PaymentGateConfigV2 - - threshold_amount: float - """Specify the threshold amount for the contract. - - Each time the contract's usage hits this amount, a threshold charge will be - initiated. - """ diff --git a/src/metronome/types/shared/subscription.py b/src/metronome/types/shared/subscription.py deleted file mode 100644 index 84ab27c6d..000000000 --- a/src/metronome/types/shared/subscription.py +++ /dev/null @@ -1,133 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from datetime import datetime -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = [ - "Subscription", - "BillingPeriods", - "BillingPeriodsCurrent", - "BillingPeriodsNext", - "BillingPeriodsPrevious", - "Proration", - "QuantitySchedule", - "SubscriptionRate", - "SubscriptionRateProduct", - "SeatConfig", -] - - -class BillingPeriodsCurrent(BaseModel): - ending_before: datetime - - starting_at: datetime - - -class BillingPeriodsNext(BaseModel): - ending_before: datetime - - starting_at: datetime - - -class BillingPeriodsPrevious(BaseModel): - ending_before: datetime - - starting_at: datetime - - -class BillingPeriods(BaseModel): - """Previous, current, and next billing periods for the subscription.""" - - current: Optional[BillingPeriodsCurrent] = None - - next: Optional[BillingPeriodsNext] = None - - previous: Optional[BillingPeriodsPrevious] = None - - -class Proration(BaseModel): - invoice_behavior: Literal["BILL_IMMEDIATELY", "BILL_ON_NEXT_COLLECTION_DATE"] - - is_prorated: bool - - -class QuantitySchedule(BaseModel): - quantity: float - - starting_at: datetime - - ending_before: Optional[datetime] = None - - -class SubscriptionRateProduct(BaseModel): - id: str - - name: str - - -class SubscriptionRate(BaseModel): - billing_frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"] - - product: SubscriptionRateProduct - - -class SeatConfig(BaseModel): - seat_group_key: str - """ - The property name, sent on usage events, that identifies the seat ID associated - with the usage event. For example, the property name might be seat_id or - user_id. The property must be set as a group key on billable metrics and a - presentation/pricing group key on contract products. This allows linked - recurring credits with an allocation per seat to be consumed by only one seat's - usage. - """ - - -class Subscription(BaseModel): - billing_periods: BillingPeriods - """Previous, current, and next billing periods for the subscription.""" - - collection_schedule: Literal["ADVANCE", "ARREARS"] - - proration: Proration - - quantity_management_mode: Literal["SEAT_BASED", "QUANTITY_ONLY"] - """Determines how the subscription's quantity is controlled. - - Defaults to QUANTITY_ONLY. **QUANTITY_ONLY**: The subscription quantity is - specified directly on the subscription. `initial_quantity` must be provided with - this option. Compatible with recurring commits/credits that use POOLED - allocation. **SEAT_BASED**: Use when you want to pass specific seat identifiers - (e.g. add user_123) to increment and decrement a subscription quantity, rather - than directly providing the quantity. You must use a **SEAT_BASED** subscription - to use a linked recurring credit with an allocation per seat. `seat_config` must - be provided with this option. - """ - - quantity_schedule: List[QuantitySchedule] - """List of quantity schedule items for the subscription. - - Only includes the current quantity and future quantity changes. - """ - - starting_at: datetime - - subscription_rate: SubscriptionRate - - id: Optional[str] = None - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: Optional[str] = None - - ending_before: Optional[datetime] = None - - fiat_credit_type_id: Optional[str] = None - - name: Optional[str] = None - - seat_config: Optional[SeatConfig] = None diff --git a/src/metronome/types/shared/tier.py b/src/metronome/types/shared/tier.py deleted file mode 100644 index 82534b52a..000000000 --- a/src/metronome/types/shared/tier.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ..._models import BaseModel - -__all__ = ["Tier"] - - -class Tier(BaseModel): - price: float - - size: Optional[float] = None diff --git a/src/metronome/types/shared/update_base_threshold_commit.py b/src/metronome/types/shared/update_base_threshold_commit.py deleted file mode 100644 index 77fc9a191..000000000 --- a/src/metronome/types/shared/update_base_threshold_commit.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ..._models import BaseModel - -__all__ = ["UpdateBaseThresholdCommit"] - - -class UpdateBaseThresholdCommit(BaseModel): - description: Optional[str] = None - - name: Optional[str] = None - """Specify the name of the line item for the threshold charge. - - If left blank, it will default to the commit product name. - """ - - product_id: Optional[str] = None - """ - The commit product that will be used to generate the line item for commit - payment. - """ diff --git a/src/metronome/types/shared_params/__init__.py b/src/metronome/types/shared_params/__init__.py deleted file mode 100644 index 8fad226fd..000000000 --- a/src/metronome/types/shared_params/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .tier import Tier as Tier -from .commit_rate import CommitRate as CommitRate -from .balance_filter import BalanceFilter as BalanceFilter -from .property_filter import PropertyFilter as PropertyFilter -from .base_usage_filter import BaseUsageFilter as BaseUsageFilter -from .event_type_filter import EventTypeFilter as EventTypeFilter -from .payment_gate_config import PaymentGateConfig as PaymentGateConfig -from .base_threshold_commit import BaseThresholdCommit as BaseThresholdCommit -from .commit_specifier_input import CommitSpecifierInput as CommitSpecifierInput -from .payment_gate_config_v2 import PaymentGateConfigV2 as PaymentGateConfigV2 -from .update_base_threshold_commit import UpdateBaseThresholdCommit as UpdateBaseThresholdCommit -from .spend_threshold_configuration import SpendThresholdConfiguration as SpendThresholdConfiguration -from .commit_hierarchy_configuration import CommitHierarchyConfiguration as CommitHierarchyConfiguration -from .spend_threshold_configuration_v2 import SpendThresholdConfigurationV2 as SpendThresholdConfigurationV2 -from .prepaid_balance_threshold_configuration import ( - PrepaidBalanceThresholdConfiguration as PrepaidBalanceThresholdConfiguration, -) -from .prepaid_balance_threshold_configuration_v2 import ( - PrepaidBalanceThresholdConfigurationV2 as PrepaidBalanceThresholdConfigurationV2, -) diff --git a/src/metronome/types/shared_params/balance_filter.py b/src/metronome/types/shared_params/balance_filter.py deleted file mode 100644 index edc38bb4c..000000000 --- a/src/metronome/types/shared_params/balance_filter.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, List -from typing_extensions import Literal, TypedDict - -from ..._types import SequenceNotStr - -__all__ = ["BalanceFilter"] - - -class BalanceFilter(TypedDict, total=False): - balance_types: List[Literal["PREPAID_COMMIT", "POSTPAID_COMMIT", "CREDIT"]] - """The balance type to filter by.""" - - custom_fields: Dict[str, str] - """Custom fields to compute balance across. Must match all custom fields""" - - ids: SequenceNotStr[str] - """Specific IDs to compute balance across.""" diff --git a/src/metronome/types/shared_params/base_threshold_commit.py b/src/metronome/types/shared_params/base_threshold_commit.py deleted file mode 100644 index 4c15bc1c6..000000000 --- a/src/metronome/types/shared_params/base_threshold_commit.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["BaseThresholdCommit"] - - -class BaseThresholdCommit(TypedDict, total=False): - product_id: Required[str] - """ - The commit product that will be used to generate the line item for commit - payment. - """ - - description: str - - name: str - """Specify the name of the line item for the threshold charge. - - If left blank, it will default to the commit product name. - """ diff --git a/src/metronome/types/shared_params/base_usage_filter.py b/src/metronome/types/shared_params/base_usage_filter.py deleted file mode 100644 index 3e72c92b1..000000000 --- a/src/metronome/types/shared_params/base_usage_filter.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ..._types import SequenceNotStr -from ..._utils import PropertyInfo - -__all__ = ["BaseUsageFilter"] - - -class BaseUsageFilter(TypedDict, total=False): - group_key: Required[str] - - group_values: Required[SequenceNotStr[str]] - - starting_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] diff --git a/src/metronome/types/shared_params/commit_hierarchy_configuration.py b/src/metronome/types/shared_params/commit_hierarchy_configuration.py deleted file mode 100644 index dae6db160..000000000 --- a/src/metronome/types/shared_params/commit_hierarchy_configuration.py +++ /dev/null @@ -1,41 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from typing_extensions import Literal, Required, TypeAlias, TypedDict - -from ..._types import SequenceNotStr - -__all__ = [ - "CommitHierarchyConfiguration", - "ChildAccess", - "ChildAccessCommitHierarchyChildAccessAll", - "ChildAccessCommitHierarchyChildAccessNone", - "ChildAccessCommitHierarchyChildAccessContractIDs", -] - - -class ChildAccessCommitHierarchyChildAccessAll(TypedDict, total=False): - type: Required[Literal["ALL"]] - - -class ChildAccessCommitHierarchyChildAccessNone(TypedDict, total=False): - type: Required[Literal["NONE"]] - - -class ChildAccessCommitHierarchyChildAccessContractIDs(TypedDict, total=False): - contract_ids: Required[SequenceNotStr[str]] - - type: Required[Literal["CONTRACT_IDS"]] - - -ChildAccess: TypeAlias = Union[ - ChildAccessCommitHierarchyChildAccessAll, - ChildAccessCommitHierarchyChildAccessNone, - ChildAccessCommitHierarchyChildAccessContractIDs, -] - - -class CommitHierarchyConfiguration(TypedDict, total=False): - child_access: Required[ChildAccess] diff --git a/src/metronome/types/shared_params/commit_rate.py b/src/metronome/types/shared_params/commit_rate.py deleted file mode 100644 index bd7b02502..000000000 --- a/src/metronome/types/shared_params/commit_rate.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable -from typing_extensions import Literal, Required, TypedDict - -from .tier import Tier - -__all__ = ["CommitRate"] - - -class CommitRate(TypedDict, total=False): - """A distinct rate on the rate card. - - You can choose to use this rate rather than list rate when consuming a credit or commit. - """ - - rate_type: Required[Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "TIERED", "TIERED_PERCENTAGE", "CUSTOM"]] - - price: float - """Commit rate price. - - For FLAT rate_type, this must be >=0. For PERCENTAGE rate_type, this is a - decimal fraction, e.g. use 0.1 for 10%; this must be >=0 and <=1. - """ - - tiers: Iterable[Tier] - """Only set for TIERED rate_type.""" diff --git a/src/metronome/types/shared_params/commit_specifier_input.py b/src/metronome/types/shared_params/commit_specifier_input.py deleted file mode 100644 index 3c1263c4b..000000000 --- a/src/metronome/types/shared_params/commit_specifier_input.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict -from typing_extensions import TypedDict - -from ..._types import SequenceNotStr - -__all__ = ["CommitSpecifierInput"] - - -class CommitSpecifierInput(TypedDict, total=False): - presentation_group_values: Dict[str, str] - """ - If provided, the specifier will apply to product usage with these set of - presentation group values. - """ - - pricing_group_values: Dict[str, str] - """ - If provided, the specifier will apply to product usage with these set of pricing - group values. - """ - - product_id: str - """ - If provided, the specifier will only apply to the product with the specified ID. - """ - - product_tags: SequenceNotStr[str] - """ - If provided, the specifier will only apply to products with all the specified - tags. - """ diff --git a/src/metronome/types/shared_params/event_type_filter.py b/src/metronome/types/shared_params/event_type_filter.py deleted file mode 100644 index 8058424a9..000000000 --- a/src/metronome/types/shared_params/event_type_filter.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -from ..._types import SequenceNotStr - -__all__ = ["EventTypeFilter"] - - -class EventTypeFilter(TypedDict, total=False): - """An optional filtering rule to match the 'event_type' property of an event.""" - - in_values: SequenceNotStr[str] - """A list of event types that are explicitly included in the billable metric. - - If specified, only events of these types will match the billable metric. Must be - non-empty if present. - """ - - not_in_values: SequenceNotStr[str] - """A list of event types that are explicitly excluded from the billable metric. - - If specified, events of these types will not match the billable metric. Must be - non-empty if present. - """ diff --git a/src/metronome/types/shared_params/payment_gate_config.py b/src/metronome/types/shared_params/payment_gate_config.py deleted file mode 100644 index d10698088..000000000 --- a/src/metronome/types/shared_params/payment_gate_config.py +++ /dev/null @@ -1,61 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["PaymentGateConfig", "PrecalculatedTaxConfig", "StripeConfig"] - - -class PrecalculatedTaxConfig(TypedDict, total=False): - """Only applicable if using PRECALCULATED as your tax type.""" - - tax_amount: Required[float] - """Amount of tax to be applied. - - This should be in the same currency and denomination as the commit's invoice - schedule - """ - - tax_name: str - """Name of the tax to be applied. - - This may be used in an invoice line item description. - """ - - -class StripeConfig(TypedDict, total=False): - """Only applicable if using STRIPE as your payment gate type.""" - - payment_type: Required[Literal["INVOICE", "PAYMENT_INTENT"]] - """If left blank, will default to INVOICE""" - - invoice_metadata: Dict[str, str] - """Metadata to be added to the Stripe invoice. - - Only applicable if using INVOICE as your payment type. - """ - - -class PaymentGateConfig(TypedDict, total=False): - payment_gate_type: Required[Literal["NONE", "STRIPE", "EXTERNAL"]] - """Gate access to the commit balance based on successful collection of payment. - - Select STRIPE for Metronome to facilitate payment via Stripe. Select EXTERNAL to - facilitate payment using your own payment integration. Select NONE if you do not - wish to payment gate the commit balance. - """ - - precalculated_tax_config: PrecalculatedTaxConfig - """Only applicable if using PRECALCULATED as your tax type.""" - - stripe_config: StripeConfig - """Only applicable if using STRIPE as your payment gate type.""" - - tax_type: Literal["NONE", "STRIPE", "ANROK", "PRECALCULATED"] - """Stripe tax is only supported for Stripe payment gateway. - - Select NONE if you do not wish Metronome to calculate tax on your behalf. - Leaving this field blank will default to NONE. - """ diff --git a/src/metronome/types/shared_params/payment_gate_config_v2.py b/src/metronome/types/shared_params/payment_gate_config_v2.py deleted file mode 100644 index ee49820db..000000000 --- a/src/metronome/types/shared_params/payment_gate_config_v2.py +++ /dev/null @@ -1,61 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["PaymentGateConfigV2", "PrecalculatedTaxConfig", "StripeConfig"] - - -class PrecalculatedTaxConfig(TypedDict, total=False): - """Only applicable if using PRECALCULATED as your tax type.""" - - tax_amount: Required[float] - """Amount of tax to be applied. - - This should be in the same currency and denomination as the commit's invoice - schedule - """ - - tax_name: str - """Name of the tax to be applied. - - This may be used in an invoice line item description. - """ - - -class StripeConfig(TypedDict, total=False): - """Only applicable if using STRIPE as your payment gateway type.""" - - payment_type: Required[Literal["INVOICE", "PAYMENT_INTENT"]] - """If left blank, will default to INVOICE""" - - invoice_metadata: Dict[str, str] - """Metadata to be added to the Stripe invoice. - - Only applicable if using INVOICE as your payment type. - """ - - -class PaymentGateConfigV2(TypedDict, total=False): - payment_gate_type: Required[Literal["NONE", "STRIPE", "EXTERNAL"]] - """Gate access to the commit balance based on successful collection of payment. - - Select STRIPE for Metronome to facilitate payment via Stripe. Select EXTERNAL to - facilitate payment using your own payment integration. Select NONE if you do not - wish to payment gate the commit balance. - """ - - precalculated_tax_config: PrecalculatedTaxConfig - """Only applicable if using PRECALCULATED as your tax type.""" - - stripe_config: StripeConfig - """Only applicable if using STRIPE as your payment gateway type.""" - - tax_type: Literal["NONE", "STRIPE", "ANROK", "PRECALCULATED"] - """Stripe tax is only supported for Stripe payment gateway. - - Select NONE if you do not wish Metronome to calculate tax on your behalf. - Leaving this field blank will default to NONE. - """ diff --git a/src/metronome/types/shared_params/prepaid_balance_threshold_configuration.py b/src/metronome/types/shared_params/prepaid_balance_threshold_configuration.py deleted file mode 100644 index 791d348d6..000000000 --- a/src/metronome/types/shared_params/prepaid_balance_threshold_configuration.py +++ /dev/null @@ -1,66 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable -from typing_extensions import Required, TypedDict - -from ..._types import SequenceNotStr -from .payment_gate_config import PaymentGateConfig -from .base_threshold_commit import BaseThresholdCommit -from .commit_specifier_input import CommitSpecifierInput - -__all__ = ["PrepaidBalanceThresholdConfiguration", "Commit"] - - -class Commit(BaseThresholdCommit, total=False): - applicable_product_ids: SequenceNotStr[str] - """Which products the threshold commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - applicable_product_tags: SequenceNotStr[str] - """Which tags the threshold commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - specifiers: Iterable[CommitSpecifierInput] - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - """ - - -class PrepaidBalanceThresholdConfiguration(TypedDict, total=False): - commit: Required[Commit] - - is_enabled: Required[bool] - """ - When set to false, the contract will not be evaluated against the - threshold_amount. Toggling to true will result an immediate evaluation, - regardless of prior state. - """ - - payment_gate_config: Required[PaymentGateConfig] - - recharge_to_amount: Required[float] - """Specify the amount the balance should be recharged to.""" - - threshold_amount: Required[float] - """Specify the threshold amount for the contract. - - Each time the contract's prepaid balance lowers to this amount, a threshold - charge will be initiated. - """ - - custom_credit_type_id: str - """ - If provided, the threshold, recharge-to amount, and the resulting threshold - commit amount will be in terms of this credit type instead of the fiat currency. - """ diff --git a/src/metronome/types/shared_params/prepaid_balance_threshold_configuration_v2.py b/src/metronome/types/shared_params/prepaid_balance_threshold_configuration_v2.py deleted file mode 100644 index bbd22786a..000000000 --- a/src/metronome/types/shared_params/prepaid_balance_threshold_configuration_v2.py +++ /dev/null @@ -1,68 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable -from typing_extensions import Required, TypedDict - -from ..._types import SequenceNotStr -from .commit_specifier_input import CommitSpecifierInput -from .payment_gate_config_v2 import PaymentGateConfigV2 -from .update_base_threshold_commit import UpdateBaseThresholdCommit - -__all__ = ["PrepaidBalanceThresholdConfigurationV2", "Commit"] - - -class Commit(UpdateBaseThresholdCommit, total=False): - applicable_product_ids: SequenceNotStr[str] - """Which products the threshold commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - applicable_product_tags: SequenceNotStr[str] - """Which tags the threshold commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - specifiers: Iterable[CommitSpecifierInput] - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - Instead, to target usage by product or product tag, pass those values in the - body of `specifiers`. - """ - - -class PrepaidBalanceThresholdConfigurationV2(TypedDict, total=False): - commit: Required[Commit] - - is_enabled: Required[bool] - """ - When set to false, the contract will not be evaluated against the - threshold_amount. Toggling to true will result an immediate evaluation, - regardless of prior state. - """ - - payment_gate_config: Required[PaymentGateConfigV2] - - recharge_to_amount: Required[float] - """Specify the amount the balance should be recharged to.""" - - threshold_amount: Required[float] - """Specify the threshold amount for the contract. - - Each time the contract's balance lowers to this amount, a threshold charge will - be initiated. - """ - - custom_credit_type_id: str - """ - If provided, the threshold, recharge-to amount, and the resulting threshold - commit amount will be in terms of this credit type instead of the fiat currency. - """ diff --git a/src/metronome/types/shared_params/property_filter.py b/src/metronome/types/shared_params/property_filter.py deleted file mode 100644 index f49f5d0ae..000000000 --- a/src/metronome/types/shared_params/property_filter.py +++ /dev/null @@ -1,38 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -from ..._types import SequenceNotStr - -__all__ = ["PropertyFilter"] - - -class PropertyFilter(TypedDict, total=False): - name: Required[str] - """The name of the event property.""" - - exists: bool - """Determines whether the property must exist in the event. - - If true, only events with this property will pass the filter. If false, only - events without this property will pass the filter. If null or omitted, the - existence of the property is optional. - """ - - in_values: SequenceNotStr[str] - """Specifies the allowed values for the property to match an event. - - An event will pass the filter only if its property value is included in this - list. If undefined, all property values will pass the filter. Must be non-empty - if present. - """ - - not_in_values: SequenceNotStr[str] - """Specifies the values that prevent an event from matching the filter. - - An event will not pass the filter if its property value is included in this - list. If null or empty, all property values will pass the filter. Must be - non-empty if present. - """ diff --git a/src/metronome/types/shared_params/spend_threshold_configuration.py b/src/metronome/types/shared_params/spend_threshold_configuration.py deleted file mode 100644 index 1747031d4..000000000 --- a/src/metronome/types/shared_params/spend_threshold_configuration.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -from .payment_gate_config import PaymentGateConfig -from .base_threshold_commit import BaseThresholdCommit - -__all__ = ["SpendThresholdConfiguration"] - - -class SpendThresholdConfiguration(TypedDict, total=False): - commit: Required[BaseThresholdCommit] - - is_enabled: Required[bool] - """ - When set to false, the contract will not be evaluated against the - threshold_amount. Toggling to true will result an immediate evaluation, - regardless of prior state. - """ - - payment_gate_config: Required[PaymentGateConfig] - - threshold_amount: Required[float] - """Specify the threshold amount for the contract. - - Each time the contract's usage hits this amount, a threshold charge will be - initiated. - """ diff --git a/src/metronome/types/shared_params/spend_threshold_configuration_v2.py b/src/metronome/types/shared_params/spend_threshold_configuration_v2.py deleted file mode 100644 index a5bd3b980..000000000 --- a/src/metronome/types/shared_params/spend_threshold_configuration_v2.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -from .payment_gate_config_v2 import PaymentGateConfigV2 -from .update_base_threshold_commit import UpdateBaseThresholdCommit - -__all__ = ["SpendThresholdConfigurationV2"] - - -class SpendThresholdConfigurationV2(TypedDict, total=False): - commit: Required[UpdateBaseThresholdCommit] - - is_enabled: Required[bool] - """ - When set to false, the contract will not be evaluated against the - threshold_amount. Toggling to true will result an immediate evaluation, - regardless of prior state. - """ - - payment_gate_config: Required[PaymentGateConfigV2] - - threshold_amount: Required[float] - """Specify the threshold amount for the contract. - - Each time the contract's usage hits this amount, a threshold charge will be - initiated. - """ diff --git a/src/metronome/types/shared_params/tier.py b/src/metronome/types/shared_params/tier.py deleted file mode 100644 index d40dc881e..000000000 --- a/src/metronome/types/shared_params/tier.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["Tier"] - - -class Tier(TypedDict, total=False): - price: Required[float] - - size: float diff --git a/src/metronome/types/shared_params/update_base_threshold_commit.py b/src/metronome/types/shared_params/update_base_threshold_commit.py deleted file mode 100644 index 82939fe32..000000000 --- a/src/metronome/types/shared_params/update_base_threshold_commit.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["UpdateBaseThresholdCommit"] - - -class UpdateBaseThresholdCommit(TypedDict, total=False): - description: str - - name: str - """Specify the name of the line item for the threshold charge. - - If left blank, it will default to the commit product name. - """ - - product_id: str - """ - The commit product that will be used to generate the line item for commit - payment. - """ diff --git a/src/metronome/types/v1/__init__.py b/src/metronome/types/v1/__init__.py deleted file mode 100644 index d1566240c..000000000 --- a/src/metronome/types/v1/__init__.py +++ /dev/null @@ -1,173 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .payment import Payment as Payment -from .customer import Customer as Customer -from .plan_detail import PlanDetail as PlanDetail -from .payment_status import PaymentStatus as PaymentStatus -from .customer_detail import CustomerDetail as CustomerDetail -from .plan_list_params import PlanListParams as PlanListParams -from .usage_list_params import UsageListParams as UsageListParams -from .plan_list_response import PlanListResponse as PlanListResponse -from .alert_create_params import AlertCreateParams as AlertCreateParams -from .credit_ledger_entry import CreditLedgerEntry as CreditLedgerEntry -from .invoice_void_params import InvoiceVoidParams as InvoiceVoidParams -from .package_list_params import PackageListParams as PackageListParams -from .payment_list_params import PaymentListParams as PaymentListParams -from .usage_ingest_params import UsageIngestParams as UsageIngestParams -from .usage_list_response import UsageListResponse as UsageListResponse -from .usage_search_params import UsageSearchParams as UsageSearchParams -from .alert_archive_params import AlertArchiveParams as AlertArchiveParams -from .contract_list_params import ContractListParams as ContractListParams -from .customer_list_params import CustomerListParams as CustomerListParams -from .alert_create_response import AlertCreateResponse as AlertCreateResponse -from .audit_log_list_params import AuditLogListParams as AuditLogListParams -from .contract_amend_params import ContractAmendParams as ContractAmendParams -from .invoice_void_response import InvoiceVoidResponse as InvoiceVoidResponse -from .package_create_params import PackageCreateParams as PackageCreateParams -from .package_list_response import PackageListResponse as PackageListResponse -from .payment_cancel_params import PaymentCancelParams as PaymentCancelParams -from .service_list_response import ServiceListResponse as ServiceListResponse -from .usage_search_response import UsageSearchResponse as UsageSearchResponse -from .alert_archive_response import AlertArchiveResponse as AlertArchiveResponse -from .contract_create_params import ContractCreateParams as ContractCreateParams -from .contract_list_response import ContractListResponse as ContractListResponse -from .customer_create_params import CustomerCreateParams as CustomerCreateParams -from .package_archive_params import PackageArchiveParams as PackageArchiveParams -from .payment_attempt_params import PaymentAttemptParams as PaymentAttemptParams -from .audit_log_list_response import AuditLogListResponse as AuditLogListResponse -from .contract_amend_response import ContractAmendResponse as ContractAmendResponse -from .contract_archive_params import ContractArchiveParams as ContractArchiveParams -from .customer_archive_params import CustomerArchiveParams as CustomerArchiveParams -from .package_create_response import PackageCreateResponse as PackageCreateResponse -from .package_retrieve_params import PackageRetrieveParams as PackageRetrieveParams -from .payment_cancel_response import PaymentCancelResponse as PaymentCancelResponse -from .contract_create_response import ContractCreateResponse as ContractCreateResponse -from .contract_retrieve_params import ContractRetrieveParams as ContractRetrieveParams -from .credit_grant_edit_params import CreditGrantEditParams as CreditGrantEditParams -from .credit_grant_list_params import CreditGrantListParams as CreditGrantListParams -from .credit_grant_void_params import CreditGrantVoidParams as CreditGrantVoidParams -from .customer_create_response import CustomerCreateResponse as CustomerCreateResponse -from .customer_set_name_params import CustomerSetNameParams as CustomerSetNameParams -from .package_archive_response import PackageArchiveResponse as PackageArchiveResponse -from .payment_attempt_response import PaymentAttemptResponse as PaymentAttemptResponse -from .plan_list_charges_params import PlanListChargesParams as PlanListChargesParams -from .pricing_unit_list_params import PricingUnitListParams as PricingUnitListParams -from .contract_archive_response import ContractArchiveResponse as ContractArchiveResponse -from .customer_archive_response import CustomerArchiveResponse as CustomerArchiveResponse -from .invoice_regenerate_params import InvoiceRegenerateParams as InvoiceRegenerateParams -from .package_retrieve_response import PackageRetrieveResponse as PackageRetrieveResponse -from .plan_get_details_response import PlanGetDetailsResponse as PlanGetDetailsResponse -from .contract_retrieve_response import ContractRetrieveResponse as ContractRetrieveResponse -from .credit_grant_create_params import CreditGrantCreateParams as CreditGrantCreateParams -from .credit_grant_edit_response import CreditGrantEditResponse as CreditGrantEditResponse -from .credit_grant_list_response import CreditGrantListResponse as CreditGrantListResponse -from .credit_grant_void_response import CreditGrantVoidResponse as CreditGrantVoidResponse -from .customer_list_costs_params import CustomerListCostsParams as CustomerListCostsParams -from .customer_retrieve_response import CustomerRetrieveResponse as CustomerRetrieveResponse -from .customer_set_name_response import CustomerSetNameResponse as CustomerSetNameResponse -from .plan_list_charges_response import PlanListChargesResponse as PlanListChargesResponse -from .plan_list_customers_params import PlanListCustomersParams as PlanListCustomersParams -from .pricing_unit_list_response import PricingUnitListResponse as PricingUnitListResponse -from .billable_metric_list_params import BillableMetricListParams as BillableMetricListParams -from .custom_field_add_key_params import CustomFieldAddKeyParams as CustomFieldAddKeyParams -from .invoice_regenerate_response import InvoiceRegenerateResponse as InvoiceRegenerateResponse -from .credit_grant_create_response import CreditGrantCreateResponse as CreditGrantCreateResponse -from .customer_list_costs_response import CustomerListCostsResponse as CustomerListCostsResponse -from .plan_list_customers_response import PlanListCustomersResponse as PlanListCustomersResponse -from .billable_metric_create_params import BillableMetricCreateParams as BillableMetricCreateParams -from .billable_metric_list_response import BillableMetricListResponse as BillableMetricListResponse -from .contract_list_balances_params import ContractListBalancesParams as ContractListBalancesParams -from .custom_field_list_keys_params import CustomFieldListKeysParams as CustomFieldListKeysParams -from .customer_update_config_params import CustomerUpdateConfigParams as CustomerUpdateConfigParams -from .usage_list_with_groups_params import UsageListWithGroupsParams as UsageListWithGroupsParams -from .billable_metric_archive_params import BillableMetricArchiveParams as BillableMetricArchiveParams -from .custom_field_remove_key_params import CustomFieldRemoveKeyParams as CustomFieldRemoveKeyParams -from .custom_field_set_values_params import CustomFieldSetValuesParams as CustomFieldSetValuesParams -from .customer_preview_events_params import CustomerPreviewEventsParams as CustomerPreviewEventsParams -from .billable_metric_create_response import BillableMetricCreateResponse as BillableMetricCreateResponse -from .contract_get_net_balance_params import ContractGetNetBalanceParams as ContractGetNetBalanceParams -from .contract_list_balances_response import ContractListBalancesResponse as ContractListBalancesResponse -from .contract_update_end_date_params import ContractUpdateEndDateParams as ContractUpdateEndDateParams -from .custom_field_list_keys_response import CustomFieldListKeysResponse as CustomFieldListKeysResponse -from .usage_list_with_groups_response import UsageListWithGroupsResponse as UsageListWithGroupsResponse -from .billable_metric_archive_response import BillableMetricArchiveResponse as BillableMetricArchiveResponse -from .contract_set_usage_filter_params import ContractSetUsageFilterParams as ContractSetUsageFilterParams -from .credit_grant_list_entries_params import CreditGrantListEntriesParams as CreditGrantListEntriesParams -from .customer_preview_events_response import CustomerPreviewEventsResponse as CustomerPreviewEventsResponse -from .rollover_amount_max_amount_param import RolloverAmountMaxAmountParam as RolloverAmountMaxAmountParam -from .billable_metric_retrieve_response import BillableMetricRetrieveResponse as BillableMetricRetrieveResponse -from .contract_get_net_balance_response import ContractGetNetBalanceResponse as ContractGetNetBalanceResponse -from .contract_update_end_date_response import ContractUpdateEndDateResponse as ContractUpdateEndDateResponse -from .custom_field_delete_values_params import CustomFieldDeleteValuesParams as CustomFieldDeleteValuesParams -from .credit_grant_list_entries_response import CreditGrantListEntriesResponse as CreditGrantListEntriesResponse -from .customer_set_ingest_aliases_params import CustomerSetIngestAliasesParams as CustomerSetIngestAliasesParams -from .dashboard_get_embeddable_url_params import DashboardGetEmbeddableURLParams as DashboardGetEmbeddableURLParams -from .rollover_amount_max_percentage_param import RolloverAmountMaxPercentageParam as RolloverAmountMaxPercentageParam -from .customer_list_billable_metrics_params import ( - CustomerListBillableMetricsParams as CustomerListBillableMetricsParams, -) -from .dashboard_get_embeddable_url_response import ( - DashboardGetEmbeddableURLResponse as DashboardGetEmbeddableURLResponse, -) -from .contract_retrieve_rate_schedule_params import ( - ContractRetrieveRateScheduleParams as ContractRetrieveRateScheduleParams, -) -from .customer_list_billable_metrics_response import ( - CustomerListBillableMetricsResponse as CustomerListBillableMetricsResponse, -) -from .contract_add_manual_balance_entry_params import ( - ContractAddManualBalanceEntryParams as ContractAddManualBalanceEntryParams, -) -from .contract_retrieve_rate_schedule_response import ( - ContractRetrieveRateScheduleResponse as ContractRetrieveRateScheduleResponse, -) -from .package_list_contracts_on_package_params import ( - PackageListContractsOnPackageParams as PackageListContractsOnPackageParams, -) -from .setting_upsert_avalara_credentials_params import ( - SettingUpsertAvalaraCredentialsParams as SettingUpsertAvalaraCredentialsParams, -) -from .contract_create_historical_invoices_params import ( - ContractCreateHistoricalInvoicesParams as ContractCreateHistoricalInvoicesParams, -) -from .customer_set_billing_configurations_params import ( - CustomerSetBillingConfigurationsParams as CustomerSetBillingConfigurationsParams, -) -from .package_list_contracts_on_package_response import ( - PackageListContractsOnPackageResponse as PackageListContractsOnPackageResponse, -) -from .setting_upsert_avalara_credentials_response import ( - SettingUpsertAvalaraCredentialsResponse as SettingUpsertAvalaraCredentialsResponse, -) -from .contract_create_historical_invoices_response import ( - ContractCreateHistoricalInvoicesResponse as ContractCreateHistoricalInvoicesResponse, -) -from .customer_set_billing_configurations_response import ( - CustomerSetBillingConfigurationsResponse as CustomerSetBillingConfigurationsResponse, -) -from .contract_schedule_pro_services_invoice_params import ( - ContractScheduleProServicesInvoiceParams as ContractScheduleProServicesInvoiceParams, -) -from .customer_archive_billing_configurations_params import ( - CustomerArchiveBillingConfigurationsParams as CustomerArchiveBillingConfigurationsParams, -) -from .contract_schedule_pro_services_invoice_response import ( - ContractScheduleProServicesInvoiceResponse as ContractScheduleProServicesInvoiceResponse, -) -from .customer_retrieve_billing_configurations_params import ( - CustomerRetrieveBillingConfigurationsParams as CustomerRetrieveBillingConfigurationsParams, -) -from .customer_archive_billing_configurations_response import ( - CustomerArchiveBillingConfigurationsResponse as CustomerArchiveBillingConfigurationsResponse, -) -from .customer_retrieve_billing_configurations_response import ( - CustomerRetrieveBillingConfigurationsResponse as CustomerRetrieveBillingConfigurationsResponse, -) -from .contract_retrieve_subscription_quantity_history_params import ( - ContractRetrieveSubscriptionQuantityHistoryParams as ContractRetrieveSubscriptionQuantityHistoryParams, -) -from .contract_retrieve_subscription_quantity_history_response import ( - ContractRetrieveSubscriptionQuantityHistoryResponse as ContractRetrieveSubscriptionQuantityHistoryResponse, -) diff --git a/src/metronome/types/v1/alert_archive_params.py b/src/metronome/types/v1/alert_archive_params.py deleted file mode 100644 index dd09e0979..000000000 --- a/src/metronome/types/v1/alert_archive_params.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["AlertArchiveParams"] - - -class AlertArchiveParams(TypedDict, total=False): - id: Required[str] - """The Metronome ID of the threshold notification""" - - release_uniqueness_key: bool - """ - If true, resets the uniqueness key on this threshold notification so it can be - re-used - """ diff --git a/src/metronome/types/v1/alert_archive_response.py b/src/metronome/types/v1/alert_archive_response.py deleted file mode 100644 index 3382a0850..000000000 --- a/src/metronome/types/v1/alert_archive_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel -from ..shared.id import ID - -__all__ = ["AlertArchiveResponse"] - - -class AlertArchiveResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/alert_create_params.py b/src/metronome/types/v1/alert_create_params.py deleted file mode 100644 index c7de69e57..000000000 --- a/src/metronome/types/v1/alert_create_params.py +++ /dev/null @@ -1,141 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable -from typing_extensions import Literal, Required, TypedDict - -from ..._types import SequenceNotStr - -__all__ = ["AlertCreateParams", "CustomFieldFilter", "GroupValue", "SeatFilter"] - - -class AlertCreateParams(TypedDict, total=False): - alert_type: Required[ - Literal[ - "low_credit_balance_reached", - "spend_threshold_reached", - "monthly_invoice_total_spend_threshold_reached", - "low_remaining_days_in_plan_reached", - "low_remaining_credit_percentage_reached", - "usage_threshold_reached", - "low_remaining_days_for_commit_segment_reached", - "low_remaining_commit_balance_reached", - "low_remaining_commit_percentage_reached", - "low_remaining_days_for_contract_credit_segment_reached", - "low_remaining_contract_credit_balance_reached", - "low_remaining_contract_credit_percentage_reached", - "low_remaining_contract_credit_and_commit_balance_reached", - "invoice_total_reached", - "low_remaining_seat_balance_reached", - ] - ] - """Type of the threshold notification""" - - name: Required[str] - """Name of the threshold notification""" - - threshold: Required[float] - """Threshold value of the notification policy. - - Depending upon the notification type, this number may represent a financial - amount, the days remaining, or a percentage reached. - """ - - billable_metric_id: str - """ - For threshold notifications of type `usage_threshold_reached`, specifies which - billable metric to track the usage for. - """ - - credit_grant_type_filters: SequenceNotStr[str] - """ - An array of strings, representing a way to filter the credit grant this - threshold notification applies to, by looking at the credit_grant_type field on - the credit grant. This field is only defined for CreditPercentage and - CreditBalance notifications - """ - - credit_type_id: str - """ID of the credit's currency, defaults to USD. - - If the specific notification type requires a pricing unit/currency, find the ID - in the [Metronome app](https://app.metronome.com/offering/pricing-units). - """ - - custom_field_filters: Iterable[CustomFieldFilter] - """ - A list of custom field filters for threshold notification types that support - advanced filtering. Only present for contract invoices. - """ - - customer_id: str - """If provided, will create this threshold notification for this specific customer. - - To create a notification for all customers, do not specify a `customer_id`. - """ - - evaluate_on_create: bool - """ - If true, the threshold notification will evaluate immediately on customers that - already meet the notification threshold. If false, it will only evaluate on - future customers that trigger the threshold. Defaults to true. - """ - - group_values: Iterable[GroupValue] - """Only present for `spend_threshold_reached` notifications. - - Scope notification to a specific group key on individual line items. - """ - - invoice_types_filter: SequenceNotStr[str] - """Only supported for invoice_total_reached threshold notifications. - - A list of invoice types to evaluate. - """ - - plan_id: str - """If provided, will create this threshold notification for this specific plan. - - To create a notification for all customers, do not specify a `plan_id`. - """ - - seat_filter: SeatFilter - """Required for `low_remaining_seat_balance_reached` notifications. - - The alert is scoped to this seat group key-value pair. - """ - - uniqueness_key: str - """Prevents the creation of duplicates. - - If a request to create a record is made with a previously used uniqueness key, a - new record will not be created and the request will fail with a 409 error. - """ - - -class CustomFieldFilter(TypedDict, total=False): - entity: Required[Literal["Contract", "Commit", "ContractCredit"]] - - key: Required[str] - - value: Required[str] - - -class GroupValue(TypedDict, total=False): - key: Required[str] - - value: str - - -class SeatFilter(TypedDict, total=False): - """Required for `low_remaining_seat_balance_reached` notifications. - - The alert is scoped to this seat group key-value pair. - """ - - seat_group_key: Required[str] - """The seat group key (e.g., "seat_id", "user_id")""" - - seat_group_value: str - """Optional seat identifier the alert is scoped to.""" diff --git a/src/metronome/types/v1/alert_create_response.py b/src/metronome/types/v1/alert_create_response.py deleted file mode 100644 index f400b7ceb..000000000 --- a/src/metronome/types/v1/alert_create_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel -from ..shared.id import ID - -__all__ = ["AlertCreateResponse"] - - -class AlertCreateResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/audit_log_list_params.py b/src/metronome/types/v1/audit_log_list_params.py deleted file mode 100644 index 0c1808a4f..000000000 --- a/src/metronome/types/v1/audit_log_list_params.py +++ /dev/null @@ -1,43 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Literal, Annotated, TypedDict - -from ..._utils import PropertyInfo - -__all__ = ["AuditLogListParams"] - - -class AuditLogListParams(TypedDict, total=False): - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """RFC 3339 timestamp (exclusive). Cannot be used with 'next_page'.""" - - limit: int - """Max number of results that should be returned""" - - next_page: str - """Cursor that indicates where the next page of results should start.""" - - resource_id: str - """Optional parameter that can be used to filter which audit logs are returned. - - If you specify resource_id, you must also specify resource_type. - """ - - resource_type: str - """Optional parameter that can be used to filter which audit logs are returned. - - If you specify resource_type, you must also specify resource_id. - """ - - sort: Literal["date_asc", "date_desc"] - """Sort order by timestamp, e.g. date_asc or date_desc. Defaults to date_asc.""" - - starting_on: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """RFC 3339 timestamp of the earliest audit log to return. - - Cannot be used with 'next_page'. - """ diff --git a/src/metronome/types/v1/audit_log_list_response.py b/src/metronome/types/v1/audit_log_list_response.py deleted file mode 100644 index 6f80a003d..000000000 --- a/src/metronome/types/v1/audit_log_list_response.py +++ /dev/null @@ -1,45 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["AuditLogListResponse", "Request", "Actor"] - - -class Request(BaseModel): - id: str - - ip: Optional[str] = None - - user_agent: Optional[str] = None - - -class Actor(BaseModel): - id: str - - name: str - - email: Optional[str] = None - - -class AuditLogListResponse(BaseModel): - id: str - - request: Request - - timestamp: datetime - - action: Optional[str] = None - - actor: Optional[Actor] = None - - description: Optional[str] = None - - resource_id: Optional[str] = None - - resource_type: Optional[str] = None - - status: Optional[Literal["success", "failure", "pending"]] = None diff --git a/src/metronome/types/v1/billable_metric_archive_params.py b/src/metronome/types/v1/billable_metric_archive_params.py deleted file mode 100644 index 1eca83a84..000000000 --- a/src/metronome/types/v1/billable_metric_archive_params.py +++ /dev/null @@ -1,11 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["BillableMetricArchiveParams"] - - -class BillableMetricArchiveParams(TypedDict, total=False): - id: Required[str] diff --git a/src/metronome/types/v1/billable_metric_archive_response.py b/src/metronome/types/v1/billable_metric_archive_response.py deleted file mode 100644 index ca983a7dd..000000000 --- a/src/metronome/types/v1/billable_metric_archive_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel -from ..shared.id import ID - -__all__ = ["BillableMetricArchiveResponse"] - - -class BillableMetricArchiveResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/billable_metric_create_params.py b/src/metronome/types/v1/billable_metric_create_params.py deleted file mode 100644 index 51881a666..000000000 --- a/src/metronome/types/v1/billable_metric_create_params.py +++ /dev/null @@ -1,54 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Iterable -from typing_extensions import Literal, Required, TypedDict - -from ..._types import SequenceNotStr -from ..shared_params.property_filter import PropertyFilter -from ..shared_params.event_type_filter import EventTypeFilter - -__all__ = ["BillableMetricCreateParams"] - - -class BillableMetricCreateParams(TypedDict, total=False): - name: Required[str] - """The display name of the billable metric.""" - - aggregation_key: str - """Specifies the type of aggregation performed on matching events. - - Required if `sql` is not provided. - """ - - aggregation_type: Literal["COUNT", "LATEST", "MAX", "SUM", "UNIQUE"] - """Specifies the type of aggregation performed on matching events.""" - - custom_fields: Dict[str, str] - """Custom fields to attach to the billable metric.""" - - event_type_filter: EventTypeFilter - """An optional filtering rule to match the 'event_type' property of an event.""" - - group_keys: Iterable[SequenceNotStr[str]] - """Property names that are used to group usage costs on an invoice. - - Each entry represents a set of properties used to slice events into distinct - buckets. - """ - - property_filters: Iterable[PropertyFilter] - """A list of filters to match events to this billable metric. - - Each filter defines a rule on an event property. All rules must pass for the - event to match the billable metric. - """ - - sql: str - """The SQL query associated with the billable metric. - - This field is mutually exclusive with aggregation_type, event_type_filter, - property_filters, aggregation_key, and group_keys. If provided, these other - fields must be omitted. - """ diff --git a/src/metronome/types/v1/billable_metric_create_response.py b/src/metronome/types/v1/billable_metric_create_response.py deleted file mode 100644 index bfbd18982..000000000 --- a/src/metronome/types/v1/billable_metric_create_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel -from ..shared.id import ID - -__all__ = ["BillableMetricCreateResponse"] - - -class BillableMetricCreateResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/billable_metric_list_params.py b/src/metronome/types/v1/billable_metric_list_params.py deleted file mode 100644 index 2e0bfe4c3..000000000 --- a/src/metronome/types/v1/billable_metric_list_params.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["BillableMetricListParams"] - - -class BillableMetricListParams(TypedDict, total=False): - include_archived: bool - """If true, the list of returned metrics will include archived metrics""" - - limit: int - """Max number of results that should be returned""" - - next_page: str - """Cursor that indicates where the next page of results should start.""" diff --git a/src/metronome/types/v1/billable_metric_list_response.py b/src/metronome/types/v1/billable_metric_list_response.py deleted file mode 100644 index ae5dd8b6f..000000000 --- a/src/metronome/types/v1/billable_metric_list_response.py +++ /dev/null @@ -1,58 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from datetime import datetime -from typing_extensions import Literal - -from ..._models import BaseModel -from ..shared.property_filter import PropertyFilter -from ..shared.event_type_filter import EventTypeFilter - -__all__ = ["BillableMetricListResponse"] - - -class BillableMetricListResponse(BaseModel): - id: str - """ID of the billable metric""" - - name: str - """The display name of the billable metric.""" - - aggregation_key: Optional[str] = None - """A key that specifies which property of the event is used to aggregate data. - - This key must be one of the property filter names and is not applicable when the - aggregation type is 'count'. - """ - - aggregation_type: Optional[Literal["COUNT", "LATEST", "MAX", "SUM", "UNIQUE"]] = None - """Specifies the type of aggregation performed on matching events.""" - - archived_at: Optional[datetime] = None - """RFC 3339 timestamp indicating when the billable metric was archived. - - If not provided, the billable metric is not archived. - """ - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - event_type_filter: Optional[EventTypeFilter] = None - """An optional filtering rule to match the 'event_type' property of an event.""" - - group_keys: Optional[List[List[str]]] = None - """Property names that are used to group usage costs on an invoice. - - Each entry represents a set of properties used to slice events into distinct - buckets. - """ - - property_filters: Optional[List[PropertyFilter]] = None - """A list of filters to match events to this billable metric. - - Each filter defines a rule on an event property. All rules must pass for the - event to match the billable metric. - """ - - sql: Optional[str] = None - """The SQL query associated with the billable metric""" diff --git a/src/metronome/types/v1/billable_metric_retrieve_response.py b/src/metronome/types/v1/billable_metric_retrieve_response.py deleted file mode 100644 index bae739ca9..000000000 --- a/src/metronome/types/v1/billable_metric_retrieve_response.py +++ /dev/null @@ -1,62 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from datetime import datetime -from typing_extensions import Literal - -from ..._models import BaseModel -from ..shared.property_filter import PropertyFilter -from ..shared.event_type_filter import EventTypeFilter - -__all__ = ["BillableMetricRetrieveResponse", "Data"] - - -class Data(BaseModel): - id: str - """ID of the billable metric""" - - name: str - """The display name of the billable metric.""" - - aggregation_key: Optional[str] = None - """A key that specifies which property of the event is used to aggregate data. - - This key must be one of the property filter names and is not applicable when the - aggregation type is 'count'. - """ - - aggregation_type: Optional[Literal["COUNT", "LATEST", "MAX", "SUM", "UNIQUE"]] = None - """Specifies the type of aggregation performed on matching events.""" - - archived_at: Optional[datetime] = None - """RFC 3339 timestamp indicating when the billable metric was archived. - - If not provided, the billable metric is not archived. - """ - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - event_type_filter: Optional[EventTypeFilter] = None - """An optional filtering rule to match the 'event_type' property of an event.""" - - group_keys: Optional[List[List[str]]] = None - """Property names that are used to group usage costs on an invoice. - - Each entry represents a set of properties used to slice events into distinct - buckets. - """ - - property_filters: Optional[List[PropertyFilter]] = None - """A list of filters to match events to this billable metric. - - Each filter defines a rule on an event property. All rules must pass for the - event to match the billable metric. - """ - - sql: Optional[str] = None - """The SQL query associated with the billable metric""" - - -class BillableMetricRetrieveResponse(BaseModel): - data: Data diff --git a/src/metronome/types/v1/contract_add_manual_balance_entry_params.py b/src/metronome/types/v1/contract_add_manual_balance_entry_params.py deleted file mode 100644 index 43ab7cb5e..000000000 --- a/src/metronome/types/v1/contract_add_manual_balance_entry_params.py +++ /dev/null @@ -1,46 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ..._utils import PropertyInfo - -__all__ = ["ContractAddManualBalanceEntryParams"] - - -class ContractAddManualBalanceEntryParams(TypedDict, total=False): - id: Required[str] - """ID of the balance (commit or credit) to update.""" - - amount: Required[float] - """Amount to add to the segment. - - A negative number will draw down from the balance. - """ - - customer_id: Required[str] - """ID of the customer whose balance is to be updated.""" - - reason: Required[str] - """Reason for the manual adjustment. This will be displayed in the ledger.""" - - segment_id: Required[str] - """ID of the segment to update.""" - - contract_id: str - """ID of the contract to update. Leave blank to update a customer level balance.""" - - per_group_amounts: Dict[str, float] - """ - If using individually configured commits/credits attached to seat managed - subscriptions, the amount to add for each seat. Must sum to total amount. - """ - - timestamp: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """RFC 3339 timestamp indicating when the manual adjustment takes place. - - If not provided, it will default to the start of the segment. - """ diff --git a/src/metronome/types/v1/contract_amend_params.py b/src/metronome/types/v1/contract_amend_params.py deleted file mode 100644 index bffd97c7b..000000000 --- a/src/metronome/types/v1/contract_amend_params.py +++ /dev/null @@ -1,851 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ..._types import SequenceNotStr -from ..._utils import PropertyInfo -from ..shared_params.tier import Tier -from ..shared_params.commit_specifier_input import CommitSpecifierInput -from ..shared_params.commit_hierarchy_configuration import CommitHierarchyConfiguration - -__all__ = [ - "ContractAmendParams", - "Commit", - "CommitAccessSchedule", - "CommitAccessScheduleScheduleItem", - "CommitInvoiceSchedule", - "CommitInvoiceScheduleRecurringSchedule", - "CommitInvoiceScheduleScheduleItem", - "CommitPaymentGateConfig", - "CommitPaymentGateConfigPrecalculatedTaxConfig", - "CommitPaymentGateConfigStripeConfig", - "Credit", - "CreditAccessSchedule", - "CreditAccessScheduleScheduleItem", - "Discount", - "DiscountSchedule", - "DiscountScheduleRecurringSchedule", - "DiscountScheduleScheduleItem", - "Override", - "OverrideOverrideSpecifier", - "OverrideOverwriteRate", - "OverrideTier", - "ProfessionalService", - "ResellerRoyalty", - "ResellerRoyaltyAwsOptions", - "ResellerRoyaltyGcpOptions", - "ScheduledCharge", - "ScheduledChargeSchedule", - "ScheduledChargeScheduleRecurringSchedule", - "ScheduledChargeScheduleScheduleItem", -] - - -class ContractAmendParams(TypedDict, total=False): - contract_id: Required[str] - """ID of the contract to amend""" - - customer_id: Required[str] - """ID of the customer whose contract is to be amended""" - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """inclusive start time for the amendment""" - - commits: Iterable[Commit] - - credits: Iterable[Credit] - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - discounts: Iterable[Discount] - """This field's availability is dependent on your client's configuration.""" - - netsuite_sales_order_id: str - """This field's availability is dependent on your client's configuration.""" - - overrides: Iterable[Override] - - professional_services: Iterable[ProfessionalService] - """This field's availability is dependent on your client's configuration.""" - - reseller_royalties: Iterable[ResellerRoyalty] - """This field's availability is dependent on your client's configuration.""" - - salesforce_opportunity_id: str - """This field's availability is dependent on your client's configuration.""" - - scheduled_charges: Iterable[ScheduledCharge] - - total_contract_value: float - """This field's availability is dependent on your client's configuration.""" - - -class CommitAccessScheduleScheduleItem(TypedDict, total=False): - amount: Required[float] - - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (exclusive)""" - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (inclusive)""" - - -class CommitAccessSchedule(TypedDict, total=False): - """Required: Schedule for distributing the commit to the customer. - - For "POSTPAID" commits only one schedule item is allowed and amount must match invoice_schedule total. - """ - - schedule_items: Required[Iterable[CommitAccessScheduleScheduleItem]] - - credit_type_id: str - """Defaults to USD (cents) if not passed""" - - -class CommitInvoiceScheduleRecurringSchedule(TypedDict, total=False): - """Enter the unit price and quantity for the charge or instead only send the amount. - - If amount is sent, the unit price is assumed to be the amount and quantity is inferred to be 1. - """ - - amount_distribution: Required[Literal["DIVIDED", "DIVIDED_ROUNDED", "EACH"]] - - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (exclusive).""" - - frequency: Required[Literal["MONTHLY", "QUARTERLY", "SEMI_ANNUAL", "ANNUAL"]] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (inclusive).""" - - amount: float - """Amount for the charge. - - Can be provided instead of unit_price and quantity. If amount is sent, the - unit_price is assumed to be the amount and quantity is inferred to be 1. - """ - - quantity: float - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount and must be specified - with unit_price. If specified amount cannot be provided. - """ - - unit_price: float - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified - with quantity. If specified amount cannot be provided. - """ - - -class CommitInvoiceScheduleScheduleItem(TypedDict, total=False): - timestamp: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """timestamp of the scheduled event""" - - amount: float - """Amount for the charge. - - Can be provided instead of unit_price and quantity. If amount is sent, the - unit_price is assumed to be the amount and quantity is inferred to be 1. - """ - - quantity: float - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount and must be specified - with unit_price. If specified amount cannot be provided. - """ - - unit_price: float - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified - with quantity. If specified amount cannot be provided. - """ - - -class CommitInvoiceSchedule(TypedDict, total=False): - """ - Required for "POSTPAID" commits: the true up invoice will be generated at this time and only one schedule item is allowed; the total must match access_schedule amount. Optional for "PREPAID" commits: if not provided, this will be a "complimentary" commit with no invoice. - """ - - credit_type_id: str - """Defaults to USD (cents) if not passed.""" - - do_not_invoice: bool - """This field is only applicable to commit invoice schedules. - - If true, this schedule will not generate an invoice. - """ - - recurring_schedule: CommitInvoiceScheduleRecurringSchedule - """Enter the unit price and quantity for the charge or instead only send the - amount. - - If amount is sent, the unit price is assumed to be the amount and quantity is - inferred to be 1. - """ - - schedule_items: Iterable[CommitInvoiceScheduleScheduleItem] - """Either provide amount or provide both unit_price and quantity.""" - - -class CommitPaymentGateConfigPrecalculatedTaxConfig(TypedDict, total=False): - """Only applicable if using PRECALCULATED as your tax type.""" - - tax_amount: Required[float] - """Amount of tax to be applied. - - This should be in the same currency and denomination as the commit's invoice - schedule - """ - - tax_name: str - """Name of the tax to be applied. - - This may be used in an invoice line item description. - """ - - -class CommitPaymentGateConfigStripeConfig(TypedDict, total=False): - """Only applicable if using STRIPE as your payment gate type.""" - - payment_type: Required[Literal["INVOICE", "PAYMENT_INTENT"]] - """If left blank, will default to INVOICE""" - - invoice_metadata: Dict[str, str] - """Metadata to be added to the Stripe invoice. - - Only applicable if using INVOICE as your payment type. - """ - - on_session_payment: bool - """If true, the payment will be made assuming the customer is present (i.e. - - on session). - - If false, the payment will be made assuming the customer is not present (i.e. - off session). For cardholders from a country with an e-mandate requirement (e.g. - India), the payment may be declined. - - If left blank, will default to false. - """ - - -class CommitPaymentGateConfig(TypedDict, total=False): - """optionally payment gate this commit""" - - payment_gate_type: Required[Literal["NONE", "STRIPE", "EXTERNAL"]] - """Gate access to the commit balance based on successful collection of payment. - - Select STRIPE for Metronome to facilitate payment via Stripe. Select EXTERNAL to - facilitate payment using your own payment integration. Select NONE if you do not - wish to payment gate the commit balance. - """ - - precalculated_tax_config: CommitPaymentGateConfigPrecalculatedTaxConfig - """Only applicable if using PRECALCULATED as your tax type.""" - - stripe_config: CommitPaymentGateConfigStripeConfig - """Only applicable if using STRIPE as your payment gate type.""" - - tax_type: Literal["NONE", "STRIPE", "ANROK", "PRECALCULATED"] - """Stripe tax is only supported for Stripe payment gateway. - - Select NONE if you do not wish Metronome to calculate tax on your behalf. - Leaving this field blank will default to NONE. - """ - - -class Commit(TypedDict, total=False): - product_id: Required[str] - - type: Required[Literal["PREPAID", "POSTPAID"]] - - access_schedule: CommitAccessSchedule - """Required: Schedule for distributing the commit to the customer. - - For "POSTPAID" commits only one schedule item is allowed and amount must match - invoice_schedule total. - """ - - amount: float - """(DEPRECATED) Use access_schedule and invoice_schedule instead.""" - - applicable_product_ids: SequenceNotStr[str] - """Which products the commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - applicable_product_tags: SequenceNotStr[str] - """Which tags the commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: str - """Used only in UI/API. It is not exposed to end customers.""" - - hierarchy_configuration: CommitHierarchyConfiguration - """Optional configuration for commit hierarchy access control""" - - invoice_schedule: CommitInvoiceSchedule - """ - Required for "POSTPAID" commits: the true up invoice will be generated at this - time and only one schedule item is allowed; the total must match access_schedule - amount. Optional for "PREPAID" commits: if not provided, this will be a - "complimentary" commit with no invoice. - """ - - name: str - """displayed on invoices""" - - netsuite_sales_order_id: str - """This field's availability is dependent on your client's configuration.""" - - payment_gate_config: CommitPaymentGateConfig - """optionally payment gate this commit""" - - priority: float - """ - If multiple commits are applicable, the one with the lower priority will apply - first. - """ - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - - rollover_fraction: float - """Fraction of unused segments that will be rolled over. Must be between 0 and 1.""" - - specifiers: Iterable[CommitSpecifierInput] - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - """ - - temporary_id: str - """ - A temporary ID for the commit that can be used to reference the commit for - commit specific overrides. - """ - - -class CreditAccessScheduleScheduleItem(TypedDict, total=False): - amount: Required[float] - - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (exclusive)""" - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (inclusive)""" - - -class CreditAccessSchedule(TypedDict, total=False): - """Schedule for distributing the credit to the customer.""" - - schedule_items: Required[Iterable[CreditAccessScheduleScheduleItem]] - - credit_type_id: str - """Defaults to USD (cents) if not passed""" - - -class Credit(TypedDict, total=False): - access_schedule: Required[CreditAccessSchedule] - """Schedule for distributing the credit to the customer.""" - - product_id: Required[str] - - applicable_product_ids: SequenceNotStr[str] - """Which products the credit applies to. - - If both applicable_product_ids and applicable_product_tags are not provided, the - credit applies to all products. - """ - - applicable_product_tags: SequenceNotStr[str] - """Which tags the credit applies to. - - If both applicable_product_ids and applicable_product_tags are not provided, the - credit applies to all products. - """ - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: str - """Used only in UI/API. It is not exposed to end customers.""" - - hierarchy_configuration: CommitHierarchyConfiguration - """Optional configuration for credit hierarchy access control""" - - name: str - """displayed on invoices""" - - netsuite_sales_order_id: str - """This field's availability is dependent on your client's configuration.""" - - priority: float - """ - If multiple credits are applicable, the one with the lower priority will apply - first. - """ - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - - rollover_fraction: float - """Fraction of unused segments that will be rolled over. Must be between 0 and 1.""" - - specifiers: Iterable[CommitSpecifierInput] - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - """ - - -class DiscountScheduleRecurringSchedule(TypedDict, total=False): - """Enter the unit price and quantity for the charge or instead only send the amount. - - If amount is sent, the unit price is assumed to be the amount and quantity is inferred to be 1. - """ - - amount_distribution: Required[Literal["DIVIDED", "DIVIDED_ROUNDED", "EACH"]] - - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (exclusive).""" - - frequency: Required[Literal["MONTHLY", "QUARTERLY", "SEMI_ANNUAL", "ANNUAL"]] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (inclusive).""" - - amount: float - """Amount for the charge. - - Can be provided instead of unit_price and quantity. If amount is sent, the - unit_price is assumed to be the amount and quantity is inferred to be 1. - """ - - quantity: float - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount and must be specified - with unit_price. If specified amount cannot be provided. - """ - - unit_price: float - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified - with quantity. If specified amount cannot be provided. - """ - - -class DiscountScheduleScheduleItem(TypedDict, total=False): - timestamp: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """timestamp of the scheduled event""" - - amount: float - """Amount for the charge. - - Can be provided instead of unit_price and quantity. If amount is sent, the - unit_price is assumed to be the amount and quantity is inferred to be 1. - """ - - quantity: float - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount and must be specified - with unit_price. If specified amount cannot be provided. - """ - - unit_price: float - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified - with quantity. If specified amount cannot be provided. - """ - - -class DiscountSchedule(TypedDict, total=False): - """Must provide either schedule_items or recurring_schedule.""" - - credit_type_id: str - """Defaults to USD (cents) if not passed.""" - - do_not_invoice: bool - """This field is only applicable to commit invoice schedules. - - If true, this schedule will not generate an invoice. - """ - - recurring_schedule: DiscountScheduleRecurringSchedule - """Enter the unit price and quantity for the charge or instead only send the - amount. - - If amount is sent, the unit price is assumed to be the amount and quantity is - inferred to be 1. - """ - - schedule_items: Iterable[DiscountScheduleScheduleItem] - """Either provide amount or provide both unit_price and quantity.""" - - -class Discount(TypedDict, total=False): - product_id: Required[str] - - schedule: Required[DiscountSchedule] - """Must provide either schedule_items or recurring_schedule.""" - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - name: str - """displayed on invoices""" - - netsuite_sales_order_id: str - """This field's availability is dependent on your client's configuration.""" - - -class OverrideOverrideSpecifier(TypedDict, total=False): - billing_frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"] - - commit_ids: SequenceNotStr[str] - """Can only be used for commit specific overrides. - - Must be used in conjunction with one of `product_id`, `product_tags`, - `pricing_group_values`, or `presentation_group_values`. If provided, the - override will only apply to the specified commits. If not provided, the override - will apply to all commits. - """ - - presentation_group_values: Dict[str, str] - """A map of group names to values. - - The override will only apply to line items with the specified presentation group - values. - """ - - pricing_group_values: Dict[str, str] - """A map of pricing group names to values. - - The override will only apply to products with the specified pricing group - values. - """ - - product_id: str - """If provided, the override will only apply to the product with the specified ID.""" - - product_tags: SequenceNotStr[str] - """ - If provided, the override will only apply to products with all the specified - tags. - """ - - recurring_commit_ids: SequenceNotStr[str] - """Can only be used for commit specific overrides. - - Must be used in conjunction with one of `product_id`, `product_tags`, - `pricing_group_values`, or `presentation_group_values`. If provided, the - override will only apply to commits created by the specified recurring commit - ids. - """ - - recurring_credit_ids: SequenceNotStr[str] - """Can only be used for commit specific overrides. - - Must be used in conjunction with one of `product_id`, `product_tags`, - `pricing_group_values`, or `presentation_group_values`. If provided, the - override will only apply to credits created by the specified recurring credit - ids. - """ - - -class OverrideOverwriteRate(TypedDict, total=False): - """Required for OVERWRITE type.""" - - rate_type: Required[Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "TIERED", "TIERED_PERCENTAGE", "CUSTOM"]] - - credit_type_id: str - - custom_rate: Dict[str, object] - """Only set for CUSTOM rate_type. - - This field is interpreted by custom rate processors. - """ - - is_prorated: bool - """Default proration configuration. - - Only valid for SUBSCRIPTION rate_type. Must be set to true. - """ - - price: float - """Default price. - - For FLAT rate_type, this must be >=0. For PERCENTAGE rate_type, this is a - decimal fraction, e.g. use 0.1 for 10%; this must be >=0 and <=1. - """ - - quantity: float - """Default quantity. For SUBSCRIPTION rate_type, this must be >=0.""" - - tiers: Iterable[Tier] - """Only set for TIERED rate_type.""" - - -class OverrideTier(TypedDict, total=False): - multiplier: Required[float] - - size: float - - -class Override(TypedDict, total=False): - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp indicating when the override will start applying (inclusive)""" - - applicable_product_tags: SequenceNotStr[str] - """tags identifying products whose rates are being overridden. - - Cannot be used in conjunction with override_specifiers. - """ - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """RFC 3339 timestamp indicating when the override will stop applying (exclusive)""" - - entitled: bool - - is_commit_specific: bool - """Indicates whether the override should only apply to commits. - - Defaults to `false`. If `true`, you can specify relevant commits in - `override_specifiers` by passing `commit_ids`. if you do not specify - `commit_ids`, then the override will apply when consuming any prepaid or - postpaid commit. - """ - - multiplier: float - """Required for MULTIPLIER type. Must be >=0.""" - - override_specifiers: Iterable[OverrideOverrideSpecifier] - """Cannot be used in conjunction with product_id or applicable_product_tags. - - If provided, the override will apply to all products with the specified - specifiers. - """ - - overwrite_rate: OverrideOverwriteRate - """Required for OVERWRITE type.""" - - priority: float - """Required for EXPLICIT multiplier prioritization scheme and all TIERED overrides. - - Under EXPLICIT prioritization, overwrites are prioritized first, and then tiered - and multiplier overrides are prioritized by their priority value (lowest first). - Must be > 0. - """ - - product_id: str - """ID of the product whose rate is being overridden. - - Cannot be used in conjunction with override_specifiers. - """ - - target: Literal["COMMIT_RATE", "LIST_RATE"] - """Indicates whether the override applies to commit rates or list rates. - - Can only be used for overrides that have `is_commit_specific` set to `true`. - Defaults to `"LIST_RATE"`. - """ - - tiers: Iterable[OverrideTier] - """Required for TIERED type. Must have at least one tier.""" - - type: Literal["OVERWRITE", "MULTIPLIER", "TIERED"] - """Overwrites are prioritized over multipliers and tiered overrides.""" - - -class ProfessionalService(TypedDict, total=False): - max_amount: Required[float] - """Maximum amount for the term.""" - - product_id: Required[str] - - quantity: Required[float] - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount. - """ - - unit_price: Required[float] - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified. - """ - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: str - - netsuite_sales_order_id: str - """This field's availability is dependent on your client's configuration.""" - - -class ResellerRoyaltyAwsOptions(TypedDict, total=False): - aws_account_number: str - - aws_offer_id: str - - aws_payer_reference_id: str - - -class ResellerRoyaltyGcpOptions(TypedDict, total=False): - gcp_account_id: str - - gcp_offer_id: str - - -class ResellerRoyalty(TypedDict, total=False): - reseller_type: Required[Literal["AWS", "AWS_PRO_SERVICE", "GCP", "GCP_PRO_SERVICE"]] - - applicable_product_ids: SequenceNotStr[str] - """Must provide at least one of applicable_product_ids or applicable_product_tags.""" - - applicable_product_tags: SequenceNotStr[str] - """Must provide at least one of applicable_product_ids or applicable_product_tags.""" - - aws_options: ResellerRoyaltyAwsOptions - - ending_before: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] - """Use null to indicate that the existing end timestamp should be removed.""" - - fraction: float - - gcp_options: ResellerRoyaltyGcpOptions - - netsuite_reseller_id: str - - reseller_contract_value: float - - starting_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - - -class ScheduledChargeScheduleRecurringSchedule(TypedDict, total=False): - """Enter the unit price and quantity for the charge or instead only send the amount. - - If amount is sent, the unit price is assumed to be the amount and quantity is inferred to be 1. - """ - - amount_distribution: Required[Literal["DIVIDED", "DIVIDED_ROUNDED", "EACH"]] - - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (exclusive).""" - - frequency: Required[Literal["MONTHLY", "QUARTERLY", "SEMI_ANNUAL", "ANNUAL"]] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (inclusive).""" - - amount: float - """Amount for the charge. - - Can be provided instead of unit_price and quantity. If amount is sent, the - unit_price is assumed to be the amount and quantity is inferred to be 1. - """ - - quantity: float - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount and must be specified - with unit_price. If specified amount cannot be provided. - """ - - unit_price: float - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified - with quantity. If specified amount cannot be provided. - """ - - -class ScheduledChargeScheduleScheduleItem(TypedDict, total=False): - timestamp: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """timestamp of the scheduled event""" - - amount: float - """Amount for the charge. - - Can be provided instead of unit_price and quantity. If amount is sent, the - unit_price is assumed to be the amount and quantity is inferred to be 1. - """ - - quantity: float - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount and must be specified - with unit_price. If specified amount cannot be provided. - """ - - unit_price: float - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified - with quantity. If specified amount cannot be provided. - """ - - -class ScheduledChargeSchedule(TypedDict, total=False): - """Must provide either schedule_items or recurring_schedule.""" - - credit_type_id: str - """Defaults to USD (cents) if not passed.""" - - do_not_invoice: bool - """This field is only applicable to commit invoice schedules. - - If true, this schedule will not generate an invoice. - """ - - recurring_schedule: ScheduledChargeScheduleRecurringSchedule - """Enter the unit price and quantity for the charge or instead only send the - amount. - - If amount is sent, the unit price is assumed to be the amount and quantity is - inferred to be 1. - """ - - schedule_items: Iterable[ScheduledChargeScheduleScheduleItem] - """Either provide amount or provide both unit_price and quantity.""" - - -class ScheduledCharge(TypedDict, total=False): - product_id: Required[str] - - schedule: Required[ScheduledChargeSchedule] - """Must provide either schedule_items or recurring_schedule.""" - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - name: str - """displayed on invoices""" - - netsuite_sales_order_id: str - """This field's availability is dependent on your client's configuration.""" diff --git a/src/metronome/types/v1/contract_amend_response.py b/src/metronome/types/v1/contract_amend_response.py deleted file mode 100644 index 7834a9edb..000000000 --- a/src/metronome/types/v1/contract_amend_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel -from ..shared.id import ID - -__all__ = ["ContractAmendResponse"] - - -class ContractAmendResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/contract_archive_params.py b/src/metronome/types/v1/contract_archive_params.py deleted file mode 100644 index 6aa1ca7b5..000000000 --- a/src/metronome/types/v1/contract_archive_params.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["ContractArchiveParams"] - - -class ContractArchiveParams(TypedDict, total=False): - contract_id: Required[str] - """ID of the contract to archive""" - - customer_id: Required[str] - """ID of the customer whose contract is to be archived""" - - void_invoices: Required[bool] - """ - If false, the existing finalized invoices will remain after the contract is - archived. - """ diff --git a/src/metronome/types/v1/contract_archive_response.py b/src/metronome/types/v1/contract_archive_response.py deleted file mode 100644 index a5b582206..000000000 --- a/src/metronome/types/v1/contract_archive_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel -from ..shared.id import ID - -__all__ = ["ContractArchiveResponse"] - - -class ContractArchiveResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/contract_create_historical_invoices_params.py b/src/metronome/types/v1/contract_create_historical_invoices_params.py deleted file mode 100644 index 5b444c204..000000000 --- a/src/metronome/types/v1/contract_create_historical_invoices_params.py +++ /dev/null @@ -1,70 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ..._utils import PropertyInfo - -__all__ = [ - "ContractCreateHistoricalInvoicesParams", - "Invoice", - "InvoiceUsageLineItem", - "InvoiceUsageLineItemSubtotalsWithQuantity", -] - - -class ContractCreateHistoricalInvoicesParams(TypedDict, total=False): - invoices: Required[Iterable[Invoice]] - - preview: Required[bool] - - -class InvoiceUsageLineItemSubtotalsWithQuantity(TypedDict, total=False): - exclusive_end_date: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - inclusive_start_date: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - quantity: Required[float] - - -class InvoiceUsageLineItem(TypedDict, total=False): - exclusive_end_date: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - inclusive_start_date: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - product_id: Required[str] - - presentation_group_values: Dict[str, str] - - pricing_group_values: Dict[str, str] - - quantity: float - - subtotals_with_quantity: Iterable[InvoiceUsageLineItemSubtotalsWithQuantity] - - -class Invoice(TypedDict, total=False): - contract_id: Required[str] - - credit_type_id: Required[str] - - customer_id: Required[str] - - exclusive_end_date: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - inclusive_start_date: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - issue_date: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - usage_line_items: Required[Iterable[InvoiceUsageLineItem]] - - billable_status: Literal["billable", "unbillable"] - """This field's availability is dependent on your client's configuration.""" - - breakdown_granularity: Literal["HOUR", "DAY"] - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" diff --git a/src/metronome/types/v1/contract_create_historical_invoices_response.py b/src/metronome/types/v1/contract_create_historical_invoices_response.py deleted file mode 100644 index 6420b12f1..000000000 --- a/src/metronome/types/v1/contract_create_historical_invoices_response.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List - -from ..._models import BaseModel -from .customers.invoice import Invoice - -__all__ = ["ContractCreateHistoricalInvoicesResponse"] - - -class ContractCreateHistoricalInvoicesResponse(BaseModel): - data: List[Invoice] diff --git a/src/metronome/types/v1/contract_create_params.py b/src/metronome/types/v1/contract_create_params.py deleted file mode 100644 index b4aa13392..000000000 --- a/src/metronome/types/v1/contract_create_params.py +++ /dev/null @@ -1,1464 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable, Optional -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ..._types import SequenceNotStr -from ..._utils import PropertyInfo -from ..shared_params.tier import Tier -from ..shared_params.base_usage_filter import BaseUsageFilter -from ..shared_params.commit_specifier_input import CommitSpecifierInput -from ..shared_params.spend_threshold_configuration import SpendThresholdConfiguration -from ..shared_params.commit_hierarchy_configuration import CommitHierarchyConfiguration -from ..shared_params.prepaid_balance_threshold_configuration import PrepaidBalanceThresholdConfiguration - -__all__ = [ - "ContractCreateParams", - "BillingProviderConfiguration", - "Commit", - "CommitAccessSchedule", - "CommitAccessScheduleScheduleItem", - "CommitInvoiceSchedule", - "CommitInvoiceScheduleRecurringSchedule", - "CommitInvoiceScheduleScheduleItem", - "CommitPaymentGateConfig", - "CommitPaymentGateConfigPrecalculatedTaxConfig", - "CommitPaymentGateConfigStripeConfig", - "Credit", - "CreditAccessSchedule", - "CreditAccessScheduleScheduleItem", - "Discount", - "DiscountSchedule", - "DiscountScheduleRecurringSchedule", - "DiscountScheduleScheduleItem", - "HierarchyConfiguration", - "HierarchyConfigurationParent", - "HierarchyConfigurationParentBehavior", - "Override", - "OverrideOverrideSpecifier", - "OverrideOverwriteRate", - "OverrideTier", - "ProfessionalService", - "RecurringCommit", - "RecurringCommitAccessAmount", - "RecurringCommitCommitDuration", - "RecurringCommitInvoiceAmount", - "RecurringCommitSubscriptionConfig", - "RecurringCommitSubscriptionConfigApplySeatIncreaseConfig", - "RecurringCredit", - "RecurringCreditAccessAmount", - "RecurringCreditCommitDuration", - "RecurringCreditSubscriptionConfig", - "RecurringCreditSubscriptionConfigApplySeatIncreaseConfig", - "ResellerRoyalty", - "ResellerRoyaltyAwsOptions", - "ResellerRoyaltyGcpOptions", - "RevenueSystemConfiguration", - "ScheduledCharge", - "ScheduledChargeSchedule", - "ScheduledChargeScheduleRecurringSchedule", - "ScheduledChargeScheduleScheduleItem", - "Subscription", - "SubscriptionProration", - "SubscriptionSubscriptionRate", - "SubscriptionSeatConfig", - "Transition", - "TransitionFutureInvoiceBehavior", - "UsageStatementSchedule", -] - - -class ContractCreateParams(TypedDict, total=False): - customer_id: Required[str] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """inclusive contract start time""" - - billing_provider_configuration: BillingProviderConfiguration - """The billing provider configuration associated with a contract. - - Provide either an ID or the provider and delivery method. - """ - - commits: Iterable[Commit] - - credits: Iterable[Credit] - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - discounts: Iterable[Discount] - """This field's availability is dependent on your client's configuration.""" - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """exclusive contract end time""" - - hierarchy_configuration: HierarchyConfiguration - - multiplier_override_prioritization: Literal["LOWEST_MULTIPLIER", "EXPLICIT"] - """ - Defaults to LOWEST_MULTIPLIER, which applies the greatest discount to list - prices automatically. EXPLICIT prioritization requires specifying priorities for - each multiplier; the one with the lowest priority value will be prioritized - first. If tiered overrides are used, prioritization must be explicit. - """ - - name: str - - net_payment_terms_days: float - - netsuite_sales_order_id: str - """This field's availability is dependent on your client's configuration.""" - - overrides: Iterable[Override] - - package_alias: str - """ - Selects the package linked to the specified alias as of the contract's start - date. Mutually exclusive with package_id. - """ - - package_id: str - """ - If provided, provisions a customer on a package instead of creating a - traditional contract. When specified, only customer_id, starting_at, package_id, - and uniqueness_key are allowed. - """ - - prepaid_balance_threshold_configuration: PrepaidBalanceThresholdConfiguration - - professional_services: Iterable[ProfessionalService] - """This field's availability is dependent on your client's configuration.""" - - rate_card_alias: str - """ - Selects the rate card linked to the specified alias as of the contract's start - date. - """ - - rate_card_id: str - - recurring_commits: Iterable[RecurringCommit] - - recurring_credits: Iterable[RecurringCredit] - - reseller_royalties: Iterable[ResellerRoyalty] - """This field's availability is dependent on your client's configuration.""" - - revenue_system_configuration: RevenueSystemConfiguration - """The revenue system configuration associated with a contract. - - Provide either an ID or the provider and delivery method. - """ - - salesforce_opportunity_id: str - """This field's availability is dependent on your client's configuration.""" - - scheduled_charges: Iterable[ScheduledCharge] - - scheduled_charges_on_usage_invoices: Literal["ALL"] - """ - Determines which scheduled and commit charges to consolidate onto the Contract's - usage invoice. The charge's `timestamp` must match the usage invoice's - `ending_before` date for consolidation to occur. This field cannot be modified - after a Contract has been created. If this field is omitted, charges will appear - on a separate invoice from usage charges. - """ - - spend_threshold_configuration: SpendThresholdConfiguration - - subscriptions: Iterable[Subscription] - """ - Optional list of - [subscriptions](https://docs.metronome.com/manage-product-access/create-subscription/) - to add to the contract. - """ - - total_contract_value: float - """This field's availability is dependent on your client's configuration.""" - - transition: Transition - - uniqueness_key: str - """Prevents the creation of duplicates. - - If a request to create a record is made with a previously used uniqueness key, a - new record will not be created and the request will fail with a 409 error. - """ - - usage_filter: BaseUsageFilter - - usage_statement_schedule: UsageStatementSchedule - - -class BillingProviderConfiguration(TypedDict, total=False): - """The billing provider configuration associated with a contract. - - Provide either an ID or the provider and delivery method. - """ - - billing_provider: Literal["aws_marketplace", "azure_marketplace", "gcp_marketplace", "stripe", "netsuite"] - """Do not specify if using billing_provider_configuration_id.""" - - billing_provider_configuration_id: str - """The Metronome ID of the billing provider configuration. - - Use when a customer has multiple configurations with the same billing provider - and delivery method. Otherwise, specify the billing_provider and - delivery_method. - """ - - delivery_method: Literal["direct_to_billing_provider", "aws_sqs", "tackle", "aws_sns"] - """Do not specify if using billing_provider_configuration_id.""" - - -class CommitAccessScheduleScheduleItem(TypedDict, total=False): - amount: Required[float] - - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (exclusive)""" - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (inclusive)""" - - -class CommitAccessSchedule(TypedDict, total=False): - """Required: Schedule for distributing the commit to the customer. - - For "POSTPAID" commits only one schedule item is allowed and amount must match invoice_schedule total. - """ - - schedule_items: Required[Iterable[CommitAccessScheduleScheduleItem]] - - credit_type_id: str - """Defaults to USD (cents) if not passed""" - - -class CommitInvoiceScheduleRecurringSchedule(TypedDict, total=False): - """Enter the unit price and quantity for the charge or instead only send the amount. - - If amount is sent, the unit price is assumed to be the amount and quantity is inferred to be 1. - """ - - amount_distribution: Required[Literal["DIVIDED", "DIVIDED_ROUNDED", "EACH"]] - - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (exclusive).""" - - frequency: Required[Literal["MONTHLY", "QUARTERLY", "SEMI_ANNUAL", "ANNUAL"]] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (inclusive).""" - - amount: float - """Amount for the charge. - - Can be provided instead of unit_price and quantity. If amount is sent, the - unit_price is assumed to be the amount and quantity is inferred to be 1. - """ - - quantity: float - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount and must be specified - with unit_price. If specified amount cannot be provided. - """ - - unit_price: float - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified - with quantity. If specified amount cannot be provided. - """ - - -class CommitInvoiceScheduleScheduleItem(TypedDict, total=False): - timestamp: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """timestamp of the scheduled event""" - - amount: float - """Amount for the charge. - - Can be provided instead of unit_price and quantity. If amount is sent, the - unit_price is assumed to be the amount and quantity is inferred to be 1. - """ - - quantity: float - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount and must be specified - with unit_price. If specified amount cannot be provided. - """ - - unit_price: float - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified - with quantity. If specified amount cannot be provided. - """ - - -class CommitInvoiceSchedule(TypedDict, total=False): - """ - Required for "POSTPAID" commits: the true up invoice will be generated at this time and only one schedule item is allowed; the total must match access_schedule amount. Optional for "PREPAID" commits: if not provided, this will be a "complimentary" commit with no invoice. - """ - - credit_type_id: str - """Defaults to USD (cents) if not passed.""" - - do_not_invoice: bool - """This field is only applicable to commit invoice schedules. - - If true, this schedule will not generate an invoice. - """ - - recurring_schedule: CommitInvoiceScheduleRecurringSchedule - """Enter the unit price and quantity for the charge or instead only send the - amount. - - If amount is sent, the unit price is assumed to be the amount and quantity is - inferred to be 1. - """ - - schedule_items: Iterable[CommitInvoiceScheduleScheduleItem] - """Either provide amount or provide both unit_price and quantity.""" - - -class CommitPaymentGateConfigPrecalculatedTaxConfig(TypedDict, total=False): - """Only applicable if using PRECALCULATED as your tax type.""" - - tax_amount: Required[float] - """Amount of tax to be applied. - - This should be in the same currency and denomination as the commit's invoice - schedule - """ - - tax_name: str - """Name of the tax to be applied. - - This may be used in an invoice line item description. - """ - - -class CommitPaymentGateConfigStripeConfig(TypedDict, total=False): - """Only applicable if using STRIPE as your payment gate type.""" - - payment_type: Required[Literal["INVOICE", "PAYMENT_INTENT"]] - """If left blank, will default to INVOICE""" - - invoice_metadata: Dict[str, str] - """Metadata to be added to the Stripe invoice. - - Only applicable if using INVOICE as your payment type. - """ - - on_session_payment: bool - """If true, the payment will be made assuming the customer is present (i.e. - - on session). - - If false, the payment will be made assuming the customer is not present (i.e. - off session). For cardholders from a country with an e-mandate requirement (e.g. - India), the payment may be declined. - - If left blank, will default to false. - """ - - -class CommitPaymentGateConfig(TypedDict, total=False): - """optionally payment gate this commit""" - - payment_gate_type: Required[Literal["NONE", "STRIPE", "EXTERNAL"]] - """Gate access to the commit balance based on successful collection of payment. - - Select STRIPE for Metronome to facilitate payment via Stripe. Select EXTERNAL to - facilitate payment using your own payment integration. Select NONE if you do not - wish to payment gate the commit balance. - """ - - precalculated_tax_config: CommitPaymentGateConfigPrecalculatedTaxConfig - """Only applicable if using PRECALCULATED as your tax type.""" - - stripe_config: CommitPaymentGateConfigStripeConfig - """Only applicable if using STRIPE as your payment gate type.""" - - tax_type: Literal["NONE", "STRIPE", "ANROK", "PRECALCULATED"] - """Stripe tax is only supported for Stripe payment gateway. - - Select NONE if you do not wish Metronome to calculate tax on your behalf. - Leaving this field blank will default to NONE. - """ - - -class Commit(TypedDict, total=False): - product_id: Required[str] - - type: Required[Literal["PREPAID", "POSTPAID"]] - - access_schedule: CommitAccessSchedule - """Required: Schedule for distributing the commit to the customer. - - For "POSTPAID" commits only one schedule item is allowed and amount must match - invoice_schedule total. - """ - - amount: float - """(DEPRECATED) Use access_schedule and invoice_schedule instead.""" - - applicable_product_ids: SequenceNotStr[str] - """Which products the commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - applicable_product_tags: SequenceNotStr[str] - """Which tags the commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: str - """Used only in UI/API. It is not exposed to end customers.""" - - hierarchy_configuration: CommitHierarchyConfiguration - """Optional configuration for commit hierarchy access control""" - - invoice_schedule: CommitInvoiceSchedule - """ - Required for "POSTPAID" commits: the true up invoice will be generated at this - time and only one schedule item is allowed; the total must match access_schedule - amount. Optional for "PREPAID" commits: if not provided, this will be a - "complimentary" commit with no invoice. - """ - - name: str - """displayed on invoices""" - - netsuite_sales_order_id: str - """This field's availability is dependent on your client's configuration.""" - - payment_gate_config: CommitPaymentGateConfig - """optionally payment gate this commit""" - - priority: float - """ - If multiple commits are applicable, the one with the lower priority will apply - first. - """ - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - - rollover_fraction: float - """Fraction of unused segments that will be rolled over. Must be between 0 and 1.""" - - specifiers: Iterable[CommitSpecifierInput] - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - """ - - temporary_id: str - """ - A temporary ID for the commit that can be used to reference the commit for - commit specific overrides. - """ - - -class CreditAccessScheduleScheduleItem(TypedDict, total=False): - amount: Required[float] - - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (exclusive)""" - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (inclusive)""" - - -class CreditAccessSchedule(TypedDict, total=False): - """Schedule for distributing the credit to the customer.""" - - schedule_items: Required[Iterable[CreditAccessScheduleScheduleItem]] - - credit_type_id: str - """Defaults to USD (cents) if not passed""" - - -class Credit(TypedDict, total=False): - access_schedule: Required[CreditAccessSchedule] - """Schedule for distributing the credit to the customer.""" - - product_id: Required[str] - - applicable_product_ids: SequenceNotStr[str] - """Which products the credit applies to. - - If both applicable_product_ids and applicable_product_tags are not provided, the - credit applies to all products. - """ - - applicable_product_tags: SequenceNotStr[str] - """Which tags the credit applies to. - - If both applicable_product_ids and applicable_product_tags are not provided, the - credit applies to all products. - """ - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: str - """Used only in UI/API. It is not exposed to end customers.""" - - hierarchy_configuration: CommitHierarchyConfiguration - """Optional configuration for credit hierarchy access control""" - - name: str - """displayed on invoices""" - - netsuite_sales_order_id: str - """This field's availability is dependent on your client's configuration.""" - - priority: float - """ - If multiple credits are applicable, the one with the lower priority will apply - first. - """ - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - - rollover_fraction: float - """Fraction of unused segments that will be rolled over. Must be between 0 and 1.""" - - specifiers: Iterable[CommitSpecifierInput] - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - """ - - -class DiscountScheduleRecurringSchedule(TypedDict, total=False): - """Enter the unit price and quantity for the charge or instead only send the amount. - - If amount is sent, the unit price is assumed to be the amount and quantity is inferred to be 1. - """ - - amount_distribution: Required[Literal["DIVIDED", "DIVIDED_ROUNDED", "EACH"]] - - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (exclusive).""" - - frequency: Required[Literal["MONTHLY", "QUARTERLY", "SEMI_ANNUAL", "ANNUAL"]] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (inclusive).""" - - amount: float - """Amount for the charge. - - Can be provided instead of unit_price and quantity. If amount is sent, the - unit_price is assumed to be the amount and quantity is inferred to be 1. - """ - - quantity: float - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount and must be specified - with unit_price. If specified amount cannot be provided. - """ - - unit_price: float - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified - with quantity. If specified amount cannot be provided. - """ - - -class DiscountScheduleScheduleItem(TypedDict, total=False): - timestamp: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """timestamp of the scheduled event""" - - amount: float - """Amount for the charge. - - Can be provided instead of unit_price and quantity. If amount is sent, the - unit_price is assumed to be the amount and quantity is inferred to be 1. - """ - - quantity: float - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount and must be specified - with unit_price. If specified amount cannot be provided. - """ - - unit_price: float - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified - with quantity. If specified amount cannot be provided. - """ - - -class DiscountSchedule(TypedDict, total=False): - """Must provide either schedule_items or recurring_schedule.""" - - credit_type_id: str - """Defaults to USD (cents) if not passed.""" - - do_not_invoice: bool - """This field is only applicable to commit invoice schedules. - - If true, this schedule will not generate an invoice. - """ - - recurring_schedule: DiscountScheduleRecurringSchedule - """Enter the unit price and quantity for the charge or instead only send the - amount. - - If amount is sent, the unit price is assumed to be the amount and quantity is - inferred to be 1. - """ - - schedule_items: Iterable[DiscountScheduleScheduleItem] - """Either provide amount or provide both unit_price and quantity.""" - - -class Discount(TypedDict, total=False): - product_id: Required[str] - - schedule: Required[DiscountSchedule] - """Must provide either schedule_items or recurring_schedule.""" - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - name: str - """displayed on invoices""" - - netsuite_sales_order_id: str - """This field's availability is dependent on your client's configuration.""" - - -class HierarchyConfigurationParent(TypedDict, total=False): - contract_id: Required[str] - - customer_id: Required[str] - - -class HierarchyConfigurationParentBehavior(TypedDict, total=False): - invoice_consolidation_type: Literal["CONCATENATE", "NONE"] - """ - Indicates the desired behavior of consolidated invoices generated by the parent - in a customer hierarchy - - **CONCATENATE**: Statements on the invoices of child customers will be appended - to the consolidated invoice - - **NONE**: Do not generate consolidated invoices - """ - - -class HierarchyConfiguration(TypedDict, total=False): - parent: HierarchyConfigurationParent - - parent_behavior: HierarchyConfigurationParentBehavior - - payer: Literal["SELF", "PARENT"] - """Indicates which customer should pay for the child's invoice charges - - **SELF**: The child pays for its own invoice charges - - **PARENT**: The parent pays for the child's invoice charges - """ - - usage_statement_behavior: Literal["CONSOLIDATE", "SEPARATE"] - """ - Indicates the behavior of the child's invoice statements on the parent's - invoices. - - **CONSOLIDATE**: Child's invoice statements will be added to parent's - consolidated invoices - - **SEPARATE**: Child's invoice statements will appear not appear on parent's - consolidated invoices - """ - - -class OverrideOverrideSpecifier(TypedDict, total=False): - billing_frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"] - - commit_ids: SequenceNotStr[str] - """Can only be used for commit specific overrides. - - Must be used in conjunction with one of `product_id`, `product_tags`, - `pricing_group_values`, or `presentation_group_values`. If provided, the - override will only apply to the specified commits. If not provided, the override - will apply to all commits. - """ - - presentation_group_values: Dict[str, str] - """A map of group names to values. - - The override will only apply to line items with the specified presentation group - values. - """ - - pricing_group_values: Dict[str, str] - """A map of pricing group names to values. - - The override will only apply to products with the specified pricing group - values. - """ - - product_id: str - """If provided, the override will only apply to the product with the specified ID.""" - - product_tags: SequenceNotStr[str] - """ - If provided, the override will only apply to products with all the specified - tags. - """ - - recurring_commit_ids: SequenceNotStr[str] - """Can only be used for commit specific overrides. - - Must be used in conjunction with one of `product_id`, `product_tags`, - `pricing_group_values`, or `presentation_group_values`. If provided, the - override will only apply to commits created by the specified recurring commit - ids. - """ - - recurring_credit_ids: SequenceNotStr[str] - """Can only be used for commit specific overrides. - - Must be used in conjunction with one of `product_id`, `product_tags`, - `pricing_group_values`, or `presentation_group_values`. If provided, the - override will only apply to credits created by the specified recurring credit - ids. - """ - - -class OverrideOverwriteRate(TypedDict, total=False): - """Required for OVERWRITE type.""" - - rate_type: Required[Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "TIERED", "TIERED_PERCENTAGE", "CUSTOM"]] - - credit_type_id: str - - custom_rate: Dict[str, object] - """Only set for CUSTOM rate_type. - - This field is interpreted by custom rate processors. - """ - - is_prorated: bool - """Default proration configuration. - - Only valid for SUBSCRIPTION rate_type. Must be set to true. - """ - - price: float - """Default price. - - For FLAT rate_type, this must be >=0. For PERCENTAGE rate_type, this is a - decimal fraction, e.g. use 0.1 for 10%; this must be >=0 and <=1. - """ - - quantity: float - """Default quantity. For SUBSCRIPTION rate_type, this must be >=0.""" - - tiers: Iterable[Tier] - """Only set for TIERED rate_type.""" - - -class OverrideTier(TypedDict, total=False): - multiplier: Required[float] - - size: float - - -class Override(TypedDict, total=False): - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp indicating when the override will start applying (inclusive)""" - - applicable_product_tags: SequenceNotStr[str] - """tags identifying products whose rates are being overridden. - - Cannot be used in conjunction with override_specifiers. - """ - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """RFC 3339 timestamp indicating when the override will stop applying (exclusive)""" - - entitled: bool - - is_commit_specific: bool - """Indicates whether the override should only apply to commits. - - Defaults to `false`. If `true`, you can specify relevant commits in - `override_specifiers` by passing `commit_ids`. if you do not specify - `commit_ids`, then the override will apply when consuming any prepaid or - postpaid commit. - """ - - multiplier: float - """Required for MULTIPLIER type. Must be >=0.""" - - override_specifiers: Iterable[OverrideOverrideSpecifier] - """Cannot be used in conjunction with product_id or applicable_product_tags. - - If provided, the override will apply to all products with the specified - specifiers. - """ - - overwrite_rate: OverrideOverwriteRate - """Required for OVERWRITE type.""" - - priority: float - """Required for EXPLICIT multiplier prioritization scheme and all TIERED overrides. - - Under EXPLICIT prioritization, overwrites are prioritized first, and then tiered - and multiplier overrides are prioritized by their priority value (lowest first). - Must be > 0. - """ - - product_id: str - """ID of the product whose rate is being overridden. - - Cannot be used in conjunction with override_specifiers. - """ - - target: Literal["COMMIT_RATE", "LIST_RATE"] - """Indicates whether the override applies to commit rates or list rates. - - Can only be used for overrides that have `is_commit_specific` set to `true`. - Defaults to `"LIST_RATE"`. - """ - - tiers: Iterable[OverrideTier] - """Required for TIERED type. Must have at least one tier.""" - - type: Literal["OVERWRITE", "MULTIPLIER", "TIERED"] - """Overwrites are prioritized over multipliers and tiered overrides.""" - - -class ProfessionalService(TypedDict, total=False): - max_amount: Required[float] - """Maximum amount for the term.""" - - product_id: Required[str] - - quantity: Required[float] - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount. - """ - - unit_price: Required[float] - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified. - """ - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: str - - netsuite_sales_order_id: str - """This field's availability is dependent on your client's configuration.""" - - -class RecurringCommitAccessAmount(TypedDict, total=False): - """The amount of commit to grant.""" - - credit_type_id: Required[str] - - unit_price: Required[float] - - quantity: float - """ - This field is required unless a subscription is attached via - `subscription_config`. - """ - - -class RecurringCommitCommitDuration(TypedDict, total=False): - """Defines the length of the access schedule for each created commit/credit. - - The value represents the number of units. Unit defaults to "PERIODS", where the length of a period is determined by the recurrence_frequency. - """ - - value: Required[float] - - unit: Literal["PERIODS"] - - -class RecurringCommitInvoiceAmount(TypedDict, total=False): - """The amount the customer should be billed for the commit. Not required.""" - - credit_type_id: Required[str] - - quantity: Required[float] - - unit_price: Required[float] - - -class RecurringCommitSubscriptionConfigApplySeatIncreaseConfig(TypedDict, total=False): - is_prorated: Required[bool] - """Indicates whether a mid-period seat increase should be prorated.""" - - -class RecurringCommitSubscriptionConfig(TypedDict, total=False): - """Attach a subscription to the recurring commit/credit.""" - - apply_seat_increase_config: Required[RecurringCommitSubscriptionConfigApplySeatIncreaseConfig] - - subscription_id: Required[str] - """ID of the subscription to configure on the recurring commit/credit.""" - - allocation: Literal["INDIVIDUAL", "POOLED"] - """If set to POOLED, allocation added per seat is pooled across the account. - - If set to INDIVIDUAL, each seat in the subscription will have its own - allocation. - """ - - -class RecurringCommit(TypedDict, total=False): - access_amount: Required[RecurringCommitAccessAmount] - """The amount of commit to grant.""" - - commit_duration: Required[RecurringCommitCommitDuration] - """Defines the length of the access schedule for each created commit/credit. - - The value represents the number of units. Unit defaults to "PERIODS", where the - length of a period is determined by the recurrence_frequency. - """ - - priority: Required[float] - """Will be passed down to the individual commits""" - - product_id: Required[str] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """determines the start time for the first commit""" - - applicable_product_ids: SequenceNotStr[str] - """Will be passed down to the individual commits""" - - applicable_product_tags: SequenceNotStr[str] - """Will be passed down to the individual commits""" - - description: str - """Will be passed down to the individual commits""" - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Determines when the contract will stop creating recurring commits. optional""" - - hierarchy_configuration: CommitHierarchyConfiguration - """Optional configuration for recurring commit/credit hierarchy access control""" - - invoice_amount: RecurringCommitInvoiceAmount - """The amount the customer should be billed for the commit. Not required.""" - - name: str - """displayed on invoices. will be passed through to the individual commits""" - - netsuite_sales_order_id: str - """Will be passed down to the individual commits""" - - proration: Literal["NONE", "FIRST", "LAST", "FIRST_AND_LAST"] - """Determines whether the first and last commit will be prorated. - - If not provided, the default is FIRST_AND_LAST (i.e. prorate both the first and - last commits). - """ - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - """Whether the created commits will use the commit rate or list rate""" - - recurrence_frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"] - """The frequency at which the recurring commits will be created. - - If not provided: - The commits will be created on the usage invoice frequency. - If provided: - The period defined in the duration will correspond to this - frequency. - Commits will be created aligned with the recurring commit's - starting_at rather than the usage invoice dates. - """ - - rollover_fraction: float - """Will be passed down to the individual commits. - - This controls how much of an individual unexpired commit will roll over upon - contract transition. Must be between 0 and 1. - """ - - specifiers: Iterable[CommitSpecifierInput] - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - """ - - subscription_config: RecurringCommitSubscriptionConfig - """Attach a subscription to the recurring commit/credit.""" - - temporary_id: str - """ - A temporary ID that can be used to reference the recurring commit for commit - specific overrides. - """ - - -class RecurringCreditAccessAmount(TypedDict, total=False): - """The amount of commit to grant.""" - - credit_type_id: Required[str] - - unit_price: Required[float] - - quantity: float - """ - This field is required unless a subscription is attached via - `subscription_config`. - """ - - -class RecurringCreditCommitDuration(TypedDict, total=False): - """Defines the length of the access schedule for each created commit/credit. - - The value represents the number of units. Unit defaults to "PERIODS", where the length of a period is determined by the recurrence_frequency. - """ - - value: Required[float] - - unit: Literal["PERIODS"] - - -class RecurringCreditSubscriptionConfigApplySeatIncreaseConfig(TypedDict, total=False): - is_prorated: Required[bool] - """Indicates whether a mid-period seat increase should be prorated.""" - - -class RecurringCreditSubscriptionConfig(TypedDict, total=False): - """Attach a subscription to the recurring commit/credit.""" - - apply_seat_increase_config: Required[RecurringCreditSubscriptionConfigApplySeatIncreaseConfig] - - subscription_id: Required[str] - """ID of the subscription to configure on the recurring commit/credit.""" - - allocation: Literal["INDIVIDUAL", "POOLED"] - """If set to POOLED, allocation added per seat is pooled across the account. - - If set to INDIVIDUAL, each seat in the subscription will have its own - allocation. - """ - - -class RecurringCredit(TypedDict, total=False): - access_amount: Required[RecurringCreditAccessAmount] - """The amount of commit to grant.""" - - commit_duration: Required[RecurringCreditCommitDuration] - """Defines the length of the access schedule for each created commit/credit. - - The value represents the number of units. Unit defaults to "PERIODS", where the - length of a period is determined by the recurrence_frequency. - """ - - priority: Required[float] - """Will be passed down to the individual commits""" - - product_id: Required[str] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """determines the start time for the first commit""" - - applicable_product_ids: SequenceNotStr[str] - """Will be passed down to the individual commits""" - - applicable_product_tags: SequenceNotStr[str] - """Will be passed down to the individual commits""" - - description: str - """Will be passed down to the individual commits""" - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Determines when the contract will stop creating recurring commits. optional""" - - hierarchy_configuration: CommitHierarchyConfiguration - """Optional configuration for recurring commit/credit hierarchy access control""" - - name: str - """displayed on invoices. will be passed through to the individual commits""" - - netsuite_sales_order_id: str - """Will be passed down to the individual commits""" - - proration: Literal["NONE", "FIRST", "LAST", "FIRST_AND_LAST"] - """Determines whether the first and last commit will be prorated. - - If not provided, the default is FIRST_AND_LAST (i.e. prorate both the first and - last commits). - """ - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - """Whether the created commits will use the commit rate or list rate""" - - recurrence_frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"] - """The frequency at which the recurring commits will be created. - - If not provided: - The commits will be created on the usage invoice frequency. - If provided: - The period defined in the duration will correspond to this - frequency. - Commits will be created aligned with the recurring commit's - starting_at rather than the usage invoice dates. - """ - - rollover_fraction: float - """Will be passed down to the individual commits. - - This controls how much of an individual unexpired commit will roll over upon - contract transition. Must be between 0 and 1. - """ - - specifiers: Iterable[CommitSpecifierInput] - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - """ - - subscription_config: RecurringCreditSubscriptionConfig - """Attach a subscription to the recurring commit/credit.""" - - temporary_id: str - """ - A temporary ID that can be used to reference the recurring commit for commit - specific overrides. - """ - - -class ResellerRoyaltyAwsOptions(TypedDict, total=False): - aws_account_number: str - - aws_offer_id: str - - aws_payer_reference_id: str - - -class ResellerRoyaltyGcpOptions(TypedDict, total=False): - gcp_account_id: str - - gcp_offer_id: str - - -class ResellerRoyalty(TypedDict, total=False): - fraction: Required[float] - - netsuite_reseller_id: Required[str] - - reseller_type: Required[Literal["AWS", "AWS_PRO_SERVICE", "GCP", "GCP_PRO_SERVICE"]] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - applicable_product_ids: SequenceNotStr[str] - """Must provide at least one of applicable_product_ids or applicable_product_tags.""" - - applicable_product_tags: SequenceNotStr[str] - """Must provide at least one of applicable_product_ids or applicable_product_tags.""" - - aws_options: ResellerRoyaltyAwsOptions - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - - gcp_options: ResellerRoyaltyGcpOptions - - reseller_contract_value: float - - -class RevenueSystemConfiguration(TypedDict, total=False): - """The revenue system configuration associated with a contract. - - Provide either an ID or the provider and delivery method. - """ - - delivery_method: Literal["direct_to_billing_provider"] - """How revenue recognition records should be delivered to the revenue system. - - Do not specify if using revenue_system_configuration_id. - """ - - provider: Literal["netsuite"] - """The system that is providing services for revenue recognition. - - Do not specify if using revenue_system_configuration_id. - """ - - revenue_system_configuration_id: str - """The Metronome ID of the revenue system configuration. - - Use when a customer has multiple configurations with the same provider and - delivery method. Otherwise, specify the provider and delivery_method. - """ - - -class ScheduledChargeScheduleRecurringSchedule(TypedDict, total=False): - """Enter the unit price and quantity for the charge or instead only send the amount. - - If amount is sent, the unit price is assumed to be the amount and quantity is inferred to be 1. - """ - - amount_distribution: Required[Literal["DIVIDED", "DIVIDED_ROUNDED", "EACH"]] - - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (exclusive).""" - - frequency: Required[Literal["MONTHLY", "QUARTERLY", "SEMI_ANNUAL", "ANNUAL"]] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (inclusive).""" - - amount: float - """Amount for the charge. - - Can be provided instead of unit_price and quantity. If amount is sent, the - unit_price is assumed to be the amount and quantity is inferred to be 1. - """ - - quantity: float - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount and must be specified - with unit_price. If specified amount cannot be provided. - """ - - unit_price: float - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified - with quantity. If specified amount cannot be provided. - """ - - -class ScheduledChargeScheduleScheduleItem(TypedDict, total=False): - timestamp: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """timestamp of the scheduled event""" - - amount: float - """Amount for the charge. - - Can be provided instead of unit_price and quantity. If amount is sent, the - unit_price is assumed to be the amount and quantity is inferred to be 1. - """ - - quantity: float - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount and must be specified - with unit_price. If specified amount cannot be provided. - """ - - unit_price: float - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified - with quantity. If specified amount cannot be provided. - """ - - -class ScheduledChargeSchedule(TypedDict, total=False): - """Must provide either schedule_items or recurring_schedule.""" - - credit_type_id: str - """Defaults to USD (cents) if not passed.""" - - do_not_invoice: bool - """This field is only applicable to commit invoice schedules. - - If true, this schedule will not generate an invoice. - """ - - recurring_schedule: ScheduledChargeScheduleRecurringSchedule - """Enter the unit price and quantity for the charge or instead only send the - amount. - - If amount is sent, the unit price is assumed to be the amount and quantity is - inferred to be 1. - """ - - schedule_items: Iterable[ScheduledChargeScheduleScheduleItem] - """Either provide amount or provide both unit_price and quantity.""" - - -class ScheduledCharge(TypedDict, total=False): - product_id: Required[str] - - schedule: Required[ScheduledChargeSchedule] - """Must provide either schedule_items or recurring_schedule.""" - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - name: str - """displayed on invoices""" - - netsuite_sales_order_id: str - """This field's availability is dependent on your client's configuration.""" - - -class SubscriptionProration(TypedDict, total=False): - invoice_behavior: Literal["BILL_IMMEDIATELY", "BILL_ON_NEXT_COLLECTION_DATE"] - """Indicates how mid-period quantity adjustments are invoiced. - - **BILL_IMMEDIATELY**: Only available when collection schedule is `ADVANCE`. The - quantity increase will be billed immediately on the scheduled date. - **BILL_ON_NEXT_COLLECTION_DATE**: The quantity increase will be billed for - in-arrears at the end of the period. - """ - - is_prorated: bool - """Indicates if the partial period will be prorated or charged a full amount.""" - - -class SubscriptionSubscriptionRate(TypedDict, total=False): - billing_frequency: Required[Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"]] - """Frequency to bill subscription with. - - Together with product_id, must match existing rate on the rate card. - """ - - product_id: Required[str] - """Must be subscription type product""" - - -class SubscriptionSeatConfig(TypedDict, total=False): - initial_seat_ids: Required[SequenceNotStr[str]] - """The initial assigned seats on this subscription.""" - - seat_group_key: Required[str] - """ - The property name, sent on usage events, that identifies the seat ID associated - with the usage event. For example, the property name might be seat_id or - user_id. The property must be set as a group key on billable metrics and a - presentation/pricing group key on contract products. This allows linked - recurring credits with an allocation per seat to be consumed by only one seat's - usage. - """ - - initial_unassigned_seats: float - """The initial amount of unassigned seats on this subscription.""" - - -class Subscription(TypedDict, total=False): - collection_schedule: Required[Literal["ADVANCE", "ARREARS"]] - - proration: Required[SubscriptionProration] - - subscription_rate: Required[SubscriptionSubscriptionRate] - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: str - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Exclusive end time for the subscription. - - If not provided, subscription inherits contract end date. - """ - - initial_quantity: float - """The initial quantity for the subscription. - - It must be non-negative value. Required if quantity_management_mode is - QUANTITY_ONLY. - """ - - name: str - - quantity_management_mode: Literal["SEAT_BASED", "QUANTITY_ONLY"] - """Determines how the subscription's quantity is controlled. - - Defaults to QUANTITY_ONLY. **QUANTITY_ONLY**: The subscription quantity is - specified directly on the subscription. `initial_quantity` must be provided with - this option. Compatible with recurring commits/credits that use POOLED - allocation. **SEAT_BASED**: Use when you want to pass specific seat identifiers - (e.g. add user_123) to increment and decrement a subscription quantity, rather - than directly providing the quantity. You must use a **SEAT_BASED** subscription - to use a linked recurring credit with an allocation per seat. `seat_config` must - be provided with this option. - """ - - seat_config: SubscriptionSeatConfig - - starting_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Inclusive start time for the subscription. - - If not provided, defaults to contract start date - """ - - temporary_id: str - """ - A temporary ID used to reference the subscription in recurring commit/credit - subscription configs created within the same payload. - """ - - -class TransitionFutureInvoiceBehavior(TypedDict, total=False): - trueup: Optional[Literal["REMOVE", "AS_IS"]] - """Controls whether future trueup invoices are billed or removed. - - Default behavior is AS_IS if not specified. - """ - - -class Transition(TypedDict, total=False): - from_contract_id: Required[str] - - type: Required[Literal["SUPERSEDE", "RENEWAL"]] - """This field's available values may vary based on your client's configuration.""" - - future_invoice_behavior: TransitionFutureInvoiceBehavior - - -class UsageStatementSchedule(TypedDict, total=False): - frequency: Required[Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"]] - - billing_anchor_date: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Required when using CUSTOM_DATE. - - This option lets you set a historical billing anchor date, aligning future - billing cycles with a chosen cadence. For example, if a contract starts on - 2024-09-15 and you set the anchor date to 2024-09-10 with a MONTHLY frequency, - the first usage statement will cover 09-15 to 10-10. Subsequent statements will - follow the 10th of each month. - """ - - day: Literal["FIRST_OF_MONTH", "CONTRACT_START", "CUSTOM_DATE"] - """If not provided, defaults to the first day of the month.""" - - invoice_generation_starting_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """The date Metronome should start generating usage invoices. - - If unspecified, contract start date will be used. This is useful to set if you - want to import historical invoices via our 'Create Historical Invoices' API - rather than having Metronome automatically generate them. - """ diff --git a/src/metronome/types/v1/contract_create_response.py b/src/metronome/types/v1/contract_create_response.py deleted file mode 100644 index 4e97367b9..000000000 --- a/src/metronome/types/v1/contract_create_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel -from ..shared.id import ID - -__all__ = ["ContractCreateResponse"] - - -class ContractCreateResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/contract_get_net_balance_params.py b/src/metronome/types/v1/contract_get_net_balance_params.py deleted file mode 100644 index a0e19599a..000000000 --- a/src/metronome/types/v1/contract_get_net_balance_params.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable -from typing_extensions import Literal, Required, TypedDict - -from ..shared_params.balance_filter import BalanceFilter - -__all__ = ["ContractGetNetBalanceParams"] - - -class ContractGetNetBalanceParams(TypedDict, total=False): - customer_id: Required[str] - """The ID of the customer.""" - - credit_type_id: str - """ - The ID of the credit type (can be fiat or a custom pricing unit) to get the - balance for. Defaults to USD (cents) if not specified. - """ - - filters: Iterable[BalanceFilter] - """ - Balance filters are OR'd together, so if a given commit or credit matches any of - the filters, it will be included in the net balance. - """ - - invoice_inclusion_mode: Literal["FINALIZED", "FINALIZED_AND_DRAFT"] - """Controls which invoices are considered when calculating the remaining balance. - - `FINALIZED` considers only deductions from finalized invoices. - `FINALIZED_AND_DRAFT` also includes deductions from pending draft invoices. - """ diff --git a/src/metronome/types/v1/contract_get_net_balance_response.py b/src/metronome/types/v1/contract_get_net_balance_response.py deleted file mode 100644 index 15771b4b7..000000000 --- a/src/metronome/types/v1/contract_get_net_balance_response.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel - -__all__ = ["ContractGetNetBalanceResponse", "Data"] - - -class Data(BaseModel): - balance: float - """ - The combined net balance that the customer has access to use at this moment - across all pertinent commits and credits. - """ - - credit_type_id: str - """ - The ID of the credit type (can be fiat or a custom pricing unit) that the - balance is for. - """ - - -class ContractGetNetBalanceResponse(BaseModel): - data: Data diff --git a/src/metronome/types/v1/contract_list_balances_params.py b/src/metronome/types/v1/contract_list_balances_params.py deleted file mode 100644 index ad08bf7be..000000000 --- a/src/metronome/types/v1/contract_list_balances_params.py +++ /dev/null @@ -1,53 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ..._utils import PropertyInfo - -__all__ = ["ContractListBalancesParams"] - - -class ContractListBalancesParams(TypedDict, total=False): - customer_id: Required[str] - - id: str - - covering_date: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Return only balances that have access schedules that "cover" the provided date""" - - effective_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Include only balances that have any access before the provided date (exclusive)""" - - exclude_zero_balances: bool - """Exclude balances with zero amounts from the response.""" - - include_archived: bool - """Include archived credits and credits from archived contracts.""" - - include_balance: bool - """Include the balance of credits and commits in the response. - - Setting this flag may cause the query to be slower. - """ - - include_contract_balances: bool - """Include balances on the contract level.""" - - include_ledgers: bool - """Include ledgers in the response. - - Setting this flag may cause the query to be slower. - """ - - limit: int - """The maximum number of commits to return. Defaults to 25.""" - - next_page: str - """The next page token from a previous response.""" - - starting_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Include only balances that have any access on or after the provided date""" diff --git a/src/metronome/types/v1/contract_list_balances_response.py b/src/metronome/types/v1/contract_list_balances_response.py deleted file mode 100644 index 30792e536..000000000 --- a/src/metronome/types/v1/contract_list_balances_response.py +++ /dev/null @@ -1,11 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Union -from typing_extensions import TypeAlias - -from ..shared.commit import Commit -from ..shared.credit import Credit - -__all__ = ["ContractListBalancesResponse"] - -ContractListBalancesResponse: TypeAlias = Union[Commit, Credit] diff --git a/src/metronome/types/v1/contract_list_params.py b/src/metronome/types/v1/contract_list_params.py deleted file mode 100644 index ce1626ab8..000000000 --- a/src/metronome/types/v1/contract_list_params.py +++ /dev/null @@ -1,45 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ..._utils import PropertyInfo - -__all__ = ["ContractListParams"] - - -class ContractListParams(TypedDict, total=False): - customer_id: Required[str] - - covering_date: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Optional RFC 3339 timestamp. - - If provided, the response will include only contracts effective on the provided - date. This cannot be provided if the starting_at filter is provided. - """ - - include_archived: bool - """Include archived contracts in the response""" - - include_balance: bool - """Include the balance of credits and commits in the response. - - Setting this flag may cause the query to be slower. - """ - - include_ledgers: bool - """Include commit ledgers in the response. - - Setting this flag may cause the query to be slower. - """ - - starting_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Optional RFC 3339 timestamp. - - If provided, the response will include only contracts where effective_at is on - or after the provided date. This cannot be provided if the covering_date filter - is provided. - """ diff --git a/src/metronome/types/v1/contract_list_response.py b/src/metronome/types/v1/contract_list_response.py deleted file mode 100644 index 5a6490d44..000000000 --- a/src/metronome/types/v1/contract_list_response.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List - -from ..._models import BaseModel -from ..shared.contract import Contract - -__all__ = ["ContractListResponse"] - - -class ContractListResponse(BaseModel): - data: List[Contract] diff --git a/src/metronome/types/v1/contract_retrieve_params.py b/src/metronome/types/v1/contract_retrieve_params.py deleted file mode 100644 index 98225c19b..000000000 --- a/src/metronome/types/v1/contract_retrieve_params.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["ContractRetrieveParams"] - - -class ContractRetrieveParams(TypedDict, total=False): - contract_id: Required[str] - - customer_id: Required[str] - - include_balance: bool - """Include the balance of credits and commits in the response. - - Setting this flag may cause the query to be slower. - """ - - include_ledgers: bool - """Include commit ledgers in the response. - - Setting this flag may cause the query to be slower. - """ diff --git a/src/metronome/types/v1/contract_retrieve_rate_schedule_params.py b/src/metronome/types/v1/contract_retrieve_rate_schedule_params.py deleted file mode 100644 index 9071ecdf9..000000000 --- a/src/metronome/types/v1/contract_retrieve_rate_schedule_params.py +++ /dev/null @@ -1,67 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ..._types import SequenceNotStr -from ..._utils import PropertyInfo - -__all__ = ["ContractRetrieveRateScheduleParams", "Selector"] - - -class ContractRetrieveRateScheduleParams(TypedDict, total=False): - contract_id: Required[str] - """ID of the contract to get the rate schedule for.""" - - customer_id: Required[str] - """ID of the customer for whose contract to get the rate schedule for.""" - - limit: int - """Max number of results that should be returned""" - - next_page: str - """Cursor that indicates where the next page of results should start.""" - - at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """optional timestamp which overlaps with the returned rate schedule segments. - - When not specified, the current timestamp will be used. - """ - - selectors: Iterable[Selector] - """ - List of rate selectors, rates matching ANY of the selectors will be included in - the response. Passing no selectors will result in all rates being returned. - """ - - -class Selector(TypedDict, total=False): - billing_frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"] - """ - Subscription rates matching the billing frequency will be included in the - response. - """ - - partial_pricing_group_values: Dict[str, str] - """ - List of pricing group key value pairs, rates containing the matching key / value - pairs will be included in the response. - """ - - pricing_group_values: Dict[str, str] - """ - List of pricing group key value pairs, rates matching all of the key / value - pairs will be included in the response. - """ - - product_id: str - """Rates matching the product id will be included in the response.""" - - product_tags: SequenceNotStr[str] - """ - List of product tags, rates matching any of the tags will be included in the - response. - """ diff --git a/src/metronome/types/v1/contract_retrieve_rate_schedule_response.py b/src/metronome/types/v1/contract_retrieve_rate_schedule_response.py deleted file mode 100644 index ed5ea2e5b..000000000 --- a/src/metronome/types/v1/contract_retrieve_rate_schedule_response.py +++ /dev/null @@ -1,51 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from datetime import datetime -from typing_extensions import Literal - -from ..._models import BaseModel -from ..shared.rate import Rate -from ..shared.commit_rate import CommitRate - -__all__ = ["ContractRetrieveRateScheduleResponse", "Data"] - - -class Data(BaseModel): - entitled: bool - - list_rate: Rate - - product_custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - product_id: str - - product_name: str - - product_tags: List[str] - - rate_card_id: str - - starting_at: datetime - - billing_frequency: Optional[Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"]] = None - - commit_rate: Optional[CommitRate] = None - """A distinct rate on the rate card. - - You can choose to use this rate rather than list rate when consuming a credit or - commit. - """ - - ending_before: Optional[datetime] = None - - override_rate: Optional[Rate] = None - - pricing_group_values: Optional[Dict[str, str]] = None - - -class ContractRetrieveRateScheduleResponse(BaseModel): - data: List[Data] - - next_page: Optional[str] = None diff --git a/src/metronome/types/v1/contract_retrieve_response.py b/src/metronome/types/v1/contract_retrieve_response.py deleted file mode 100644 index aec7f8828..000000000 --- a/src/metronome/types/v1/contract_retrieve_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel -from ..shared.contract import Contract - -__all__ = ["ContractRetrieveResponse"] - - -class ContractRetrieveResponse(BaseModel): - data: Contract diff --git a/src/metronome/types/v1/contract_retrieve_subscription_quantity_history_params.py b/src/metronome/types/v1/contract_retrieve_subscription_quantity_history_params.py deleted file mode 100644 index f51322686..000000000 --- a/src/metronome/types/v1/contract_retrieve_subscription_quantity_history_params.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["ContractRetrieveSubscriptionQuantityHistoryParams"] - - -class ContractRetrieveSubscriptionQuantityHistoryParams(TypedDict, total=False): - contract_id: Required[str] - - customer_id: Required[str] - - subscription_id: Required[str] diff --git a/src/metronome/types/v1/contract_retrieve_subscription_quantity_history_response.py b/src/metronome/types/v1/contract_retrieve_subscription_quantity_history_response.py deleted file mode 100644 index 7f048c1c4..000000000 --- a/src/metronome/types/v1/contract_retrieve_subscription_quantity_history_response.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime - -from ..._models import BaseModel - -__all__ = ["ContractRetrieveSubscriptionQuantityHistoryResponse", "Data", "DataHistory", "DataHistoryData"] - - -class DataHistoryData(BaseModel): - quantity: float - - total: float - - unit_price: float - - -class DataHistory(BaseModel): - data: List[DataHistoryData] - - starting_at: datetime - - -class Data(BaseModel): - fiat_credit_type_id: Optional[str] = None - - history: Optional[List[DataHistory]] = None - - subscription_id: Optional[str] = None - - -class ContractRetrieveSubscriptionQuantityHistoryResponse(BaseModel): - data: Data diff --git a/src/metronome/types/v1/contract_schedule_pro_services_invoice_params.py b/src/metronome/types/v1/contract_schedule_pro_services_invoice_params.py deleted file mode 100644 index c8363f31d..000000000 --- a/src/metronome/types/v1/contract_schedule_pro_services_invoice_params.py +++ /dev/null @@ -1,62 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ..._utils import PropertyInfo - -__all__ = ["ContractScheduleProServicesInvoiceParams", "LineItem"] - - -class ContractScheduleProServicesInvoiceParams(TypedDict, total=False): - contract_id: Required[str] - - customer_id: Required[str] - - issued_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """The date the invoice is issued""" - - line_items: Required[Iterable[LineItem]] - """Each line requires an amount or both unit_price and quantity.""" - - netsuite_invoice_header_end: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """The end date of the invoice header in Netsuite""" - - netsuite_invoice_header_start: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """The start date of the invoice header in Netsuite""" - - -class LineItem(TypedDict, total=False): - """Describes the line item for a professional service charge on an invoice.""" - - professional_service_id: Required[str] - - amendment_id: str - """If the professional_service_id was added on an amendment, this is required.""" - - amount: float - """Amount for the term on the new invoice.""" - - metadata: str - """For client use.""" - - netsuite_invoice_billing_end: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """The end date for the billing period on the invoice.""" - - netsuite_invoice_billing_start: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """The start date for the billing period on the invoice.""" - - quantity: float - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount. - """ - - unit_price: float - """If specified, this overrides the unit price on the pro service term. - - Must also provide quantity (but not amount) if providing unit_price. - """ diff --git a/src/metronome/types/v1/contract_schedule_pro_services_invoice_response.py b/src/metronome/types/v1/contract_schedule_pro_services_invoice_response.py deleted file mode 100644 index 5cd29ce09..000000000 --- a/src/metronome/types/v1/contract_schedule_pro_services_invoice_response.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List - -from ..._models import BaseModel -from .customers.invoice import Invoice - -__all__ = ["ContractScheduleProServicesInvoiceResponse"] - - -class ContractScheduleProServicesInvoiceResponse(BaseModel): - data: List[Invoice] diff --git a/src/metronome/types/v1/contract_set_usage_filter_params.py b/src/metronome/types/v1/contract_set_usage_filter_params.py deleted file mode 100644 index d1ccb6d32..000000000 --- a/src/metronome/types/v1/contract_set_usage_filter_params.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ..._types import SequenceNotStr -from ..._utils import PropertyInfo - -__all__ = ["ContractSetUsageFilterParams"] - - -class ContractSetUsageFilterParams(TypedDict, total=False): - contract_id: Required[str] - - customer_id: Required[str] - - group_key: Required[str] - - group_values: Required[SequenceNotStr[str]] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] diff --git a/src/metronome/types/v1/contract_update_end_date_params.py b/src/metronome/types/v1/contract_update_end_date_params.py deleted file mode 100644 index ce71038db..000000000 --- a/src/metronome/types/v1/contract_update_end_date_params.py +++ /dev/null @@ -1,33 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ..._utils import PropertyInfo - -__all__ = ["ContractUpdateEndDateParams"] - - -class ContractUpdateEndDateParams(TypedDict, total=False): - contract_id: Required[str] - """ID of the contract to update""" - - customer_id: Required[str] - """ID of the customer whose contract is to be updated""" - - allow_ending_before_finalized_invoice: bool - """ - If true, allows setting the contract end date earlier than the end_timestamp of - existing finalized invoices. Finalized invoices will be unchanged; if you want - to incorporate the new end date, you can void and regenerate finalized usage - invoices. Defaults to true. - """ - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """RFC 3339 timestamp indicating when the contract will end (exclusive). - - If not provided, the contract will be updated to be open-ended. - """ diff --git a/src/metronome/types/v1/contract_update_end_date_response.py b/src/metronome/types/v1/contract_update_end_date_response.py deleted file mode 100644 index f49748526..000000000 --- a/src/metronome/types/v1/contract_update_end_date_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel -from ..shared.id import ID - -__all__ = ["ContractUpdateEndDateResponse"] - - -class ContractUpdateEndDateResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/contracts/__init__.py b/src/metronome/types/v1/contracts/__init__.py deleted file mode 100644 index ca37d0273..000000000 --- a/src/metronome/types/v1/contracts/__init__.py +++ /dev/null @@ -1,38 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .quantity_rounding import QuantityRounding as QuantityRounding -from .product_list_params import ProductListParams as ProductListParams -from .quantity_conversion import QuantityConversion as QuantityConversion -from .product_create_params import ProductCreateParams as ProductCreateParams -from .product_list_response import ProductListResponse as ProductListResponse -from .product_update_params import ProductUpdateParams as ProductUpdateParams -from .rate_card_list_params import RateCardListParams as RateCardListParams -from .product_archive_params import ProductArchiveParams as ProductArchiveParams -from .product_create_response import ProductCreateResponse as ProductCreateResponse -from .product_list_item_state import ProductListItemState as ProductListItemState -from .product_retrieve_params import ProductRetrieveParams as ProductRetrieveParams -from .product_update_response import ProductUpdateResponse as ProductUpdateResponse -from .quantity_rounding_param import QuantityRoundingParam as QuantityRoundingParam -from .rate_card_create_params import RateCardCreateParams as RateCardCreateParams -from .rate_card_list_response import RateCardListResponse as RateCardListResponse -from .rate_card_update_params import RateCardUpdateParams as RateCardUpdateParams -from .product_archive_response import ProductArchiveResponse as ProductArchiveResponse -from .rate_card_archive_params import RateCardArchiveParams as RateCardArchiveParams -from .product_retrieve_response import ProductRetrieveResponse as ProductRetrieveResponse -from .quantity_conversion_param import QuantityConversionParam as QuantityConversionParam -from .rate_card_create_response import RateCardCreateResponse as RateCardCreateResponse -from .rate_card_retrieve_params import RateCardRetrieveParams as RateCardRetrieveParams -from .rate_card_update_response import RateCardUpdateResponse as RateCardUpdateResponse -from .rate_card_archive_response import RateCardArchiveResponse as RateCardArchiveResponse -from .rate_card_retrieve_response import RateCardRetrieveResponse as RateCardRetrieveResponse -from .named_schedule_update_params import NamedScheduleUpdateParams as NamedScheduleUpdateParams -from .named_schedule_retrieve_params import NamedScheduleRetrieveParams as NamedScheduleRetrieveParams -from .named_schedule_retrieve_response import NamedScheduleRetrieveResponse as NamedScheduleRetrieveResponse -from .rate_card_retrieve_rate_schedule_params import ( - RateCardRetrieveRateScheduleParams as RateCardRetrieveRateScheduleParams, -) -from .rate_card_retrieve_rate_schedule_response import ( - RateCardRetrieveRateScheduleResponse as RateCardRetrieveRateScheduleResponse, -) diff --git a/src/metronome/types/v1/contracts/named_schedule_retrieve_params.py b/src/metronome/types/v1/contracts/named_schedule_retrieve_params.py deleted file mode 100644 index ec941fd77..000000000 --- a/src/metronome/types/v1/contracts/named_schedule_retrieve_params.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ...._utils import PropertyInfo - -__all__ = ["NamedScheduleRetrieveParams"] - - -class NamedScheduleRetrieveParams(TypedDict, total=False): - rate_card_id: Required[str] - """ID of the rate card whose named schedule is to be retrieved""" - - schedule_name: Required[str] - """The identifier for the schedule to be retrieved""" - - covering_date: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """ - If provided, at most one schedule segment will be returned (the one that covers - this date). If not provided, all segments will be returned. - """ diff --git a/src/metronome/types/v1/contracts/named_schedule_retrieve_response.py b/src/metronome/types/v1/contracts/named_schedule_retrieve_response.py deleted file mode 100644 index d6b9cecc0..000000000 --- a/src/metronome/types/v1/contracts/named_schedule_retrieve_response.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime - -from ...._models import BaseModel - -__all__ = ["NamedScheduleRetrieveResponse", "Data"] - - -class Data(BaseModel): - starting_at: datetime - - value: object - - ending_before: Optional[datetime] = None - - -class NamedScheduleRetrieveResponse(BaseModel): - data: List[Data] diff --git a/src/metronome/types/v1/contracts/named_schedule_update_params.py b/src/metronome/types/v1/contracts/named_schedule_update_params.py deleted file mode 100644 index d43f3c1ca..000000000 --- a/src/metronome/types/v1/contracts/named_schedule_update_params.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ...._utils import PropertyInfo - -__all__ = ["NamedScheduleUpdateParams"] - - -class NamedScheduleUpdateParams(TypedDict, total=False): - rate_card_id: Required[str] - """ID of the rate card whose named schedule is to be updated""" - - schedule_name: Required[str] - """The identifier for the schedule to be updated""" - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - value: Required[object] - """The value to set for the named schedule. - - The structure of this object is specific to the named schedule. - """ - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] diff --git a/src/metronome/types/v1/contracts/product_archive_params.py b/src/metronome/types/v1/contracts/product_archive_params.py deleted file mode 100644 index 90ccc5656..000000000 --- a/src/metronome/types/v1/contracts/product_archive_params.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["ProductArchiveParams"] - - -class ProductArchiveParams(TypedDict, total=False): - product_id: Required[str] - """ID of the product to be archived""" diff --git a/src/metronome/types/v1/contracts/product_archive_response.py b/src/metronome/types/v1/contracts/product_archive_response.py deleted file mode 100644 index 3baeec3ba..000000000 --- a/src/metronome/types/v1/contracts/product_archive_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel -from ...shared.id import ID - -__all__ = ["ProductArchiveResponse"] - - -class ProductArchiveResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/contracts/product_create_params.py b/src/metronome/types/v1/contracts/product_create_params.py deleted file mode 100644 index c4dd13c7b..000000000 --- a/src/metronome/types/v1/contracts/product_create_params.py +++ /dev/null @@ -1,90 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Optional -from typing_extensions import Literal, Required, TypedDict - -from ...._types import SequenceNotStr -from .quantity_rounding_param import QuantityRoundingParam -from .quantity_conversion_param import QuantityConversionParam - -__all__ = ["ProductCreateParams"] - - -class ProductCreateParams(TypedDict, total=False): - name: Required[str] - """displayed on invoices""" - - type: Required[Literal["FIXED", "USAGE", "COMPOSITE", "SUBSCRIPTION", "PROFESSIONAL_SERVICE", "PRO_SERVICE"]] - - billable_metric_id: str - """Required for USAGE products""" - - composite_product_ids: SequenceNotStr[str] - """Required for COMPOSITE products""" - - composite_tags: SequenceNotStr[str] - """Required for COMPOSITE products""" - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - exclude_free_usage: bool - """Beta feature only available for composite products. - - If true, products with $0 will not be included when computing composite usage. - Defaults to false - """ - - is_refundable: bool - """This field's availability is dependent on your client's configuration. - - Defaults to true. - """ - - netsuite_internal_item_id: str - """This field's availability is dependent on your client's configuration.""" - - netsuite_overage_item_id: str - """This field's availability is dependent on your client's configuration.""" - - presentation_group_key: SequenceNotStr[str] - """For USAGE products only. - - Groups usage line items on invoices. The superset of values in the pricing group - key and presentation group key must be set as one compound group key on the - billable metric. - """ - - pricing_group_key: SequenceNotStr[str] - """For USAGE products only. - - If set, pricing for this product will be determined for each pricing_group_key - value, as opposed to the product as a whole. The superset of values in the - pricing group key and presentation group key must be set as one compound group - key on the billable metric. - """ - - quantity_conversion: Optional[QuantityConversionParam] - """Optional. - - Only valid for USAGE products. If provided, the quantity will be converted using - the provided conversion factor and operation. For example, if the operation is - "multiply" and the conversion factor is 100, then the quantity will be - multiplied by 100. This can be used in cases where data is sent in one unit and - priced in another. For example, data could be sent in MB and priced in GB. In - this case, the conversion factor would be 1024 and the operation would be - "divide". - """ - - quantity_rounding: Optional[QuantityRoundingParam] - """Optional. - - Only valid for USAGE products. If provided, the quantity will be rounded using - the provided rounding method and decimal places. For example, if the method is - "round up" and the decimal places is 0, then the quantity will be rounded up to - the nearest integer. - """ - - tags: SequenceNotStr[str] diff --git a/src/metronome/types/v1/contracts/product_create_response.py b/src/metronome/types/v1/contracts/product_create_response.py deleted file mode 100644 index f434ca2b9..000000000 --- a/src/metronome/types/v1/contracts/product_create_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel -from ...shared.id import ID - -__all__ = ["ProductCreateResponse"] - - -class ProductCreateResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/contracts/product_list_item_state.py b/src/metronome/types/v1/contracts/product_list_item_state.py deleted file mode 100644 index 150f3a793..000000000 --- a/src/metronome/types/v1/contracts/product_list_item_state.py +++ /dev/null @@ -1,77 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime - -from ...._models import BaseModel -from .quantity_rounding import QuantityRounding -from .quantity_conversion import QuantityConversion - -__all__ = ["ProductListItemState"] - - -class ProductListItemState(BaseModel): - created_at: datetime - - created_by: str - - name: str - - billable_metric_id: Optional[str] = None - - composite_product_ids: Optional[List[str]] = None - - composite_tags: Optional[List[str]] = None - - exclude_free_usage: Optional[bool] = None - - is_refundable: Optional[bool] = None - """This field's availability is dependent on your client's configuration.""" - - netsuite_internal_item_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - netsuite_overage_item_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - presentation_group_key: Optional[List[str]] = None - """For USAGE products only. - - Groups usage line items on invoices. The superset of values in the pricing group - key and presentation group key must be set as one compound group key on the - billable metric. - """ - - pricing_group_key: Optional[List[str]] = None - """For USAGE products only. - - If set, pricing for this product will be determined for each pricing_group_key - value, as opposed to the product as a whole. The superset of values in the - pricing group key and presentation group key must be set as one compound group - key on the billable metric. - """ - - quantity_conversion: Optional[QuantityConversion] = None - """Optional. - - Only valid for USAGE products. If provided, the quantity will be converted using - the provided conversion factor and operation. For example, if the operation is - "multiply" and the conversion factor is 100, then the quantity will be - multiplied by 100. This can be used in cases where data is sent in one unit and - priced in another. For example, data could be sent in MB and priced in GB. In - this case, the conversion factor would be 1024 and the operation would be - "divide". - """ - - quantity_rounding: Optional[QuantityRounding] = None - """Optional. - - Only valid for USAGE products. If provided, the quantity will be rounded using - the provided rounding method and decimal places. For example, if the method is - "round up" and the decimal places is 0, then the quantity will be rounded up to - the nearest integer. - """ - - starting_at: Optional[datetime] = None - - tags: Optional[List[str]] = None diff --git a/src/metronome/types/v1/contracts/product_list_params.py b/src/metronome/types/v1/contracts/product_list_params.py deleted file mode 100644 index caa9c458d..000000000 --- a/src/metronome/types/v1/contracts/product_list_params.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, TypedDict - -__all__ = ["ProductListParams"] - - -class ProductListParams(TypedDict, total=False): - limit: int - """Max number of results that should be returned""" - - next_page: str - """Cursor that indicates where the next page of results should start.""" - - archive_filter: Literal["ARCHIVED", "NOT_ARCHIVED", "ALL"] - """Filter options for the product list. If not provided, defaults to not archived.""" diff --git a/src/metronome/types/v1/contracts/product_list_response.py b/src/metronome/types/v1/contracts/product_list_response.py deleted file mode 100644 index 042525a65..000000000 --- a/src/metronome/types/v1/contracts/product_list_response.py +++ /dev/null @@ -1,95 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from datetime import datetime -from typing_extensions import Literal - -from ...._models import BaseModel -from .quantity_rounding import QuantityRounding -from .quantity_conversion import QuantityConversion -from .product_list_item_state import ProductListItemState - -__all__ = ["ProductListResponse", "Update"] - - -class Update(BaseModel): - created_at: datetime - - created_by: str - - billable_metric_id: Optional[str] = None - - composite_product_ids: Optional[List[str]] = None - - composite_tags: Optional[List[str]] = None - - exclude_free_usage: Optional[bool] = None - - is_refundable: Optional[bool] = None - - name: Optional[str] = None - - netsuite_internal_item_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - netsuite_overage_item_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - presentation_group_key: Optional[List[str]] = None - """For USAGE products only. - - Groups usage line items on invoices. The superset of values in the pricing group - key and presentation group key must be set as one compound group key on the - billable metric. - """ - - pricing_group_key: Optional[List[str]] = None - """For USAGE products only. - - If set, pricing for this product will be determined for each pricing_group_key - value, as opposed to the product as a whole. The superset of values in the - pricing group key and presentation group key must be set as one compound group - key on the billable metric. - """ - - quantity_conversion: Optional[QuantityConversion] = None - """Optional. - - Only valid for USAGE products. If provided, the quantity will be converted using - the provided conversion factor and operation. For example, if the operation is - "multiply" and the conversion factor is 100, then the quantity will be - multiplied by 100. This can be used in cases where data is sent in one unit and - priced in another. For example, data could be sent in MB and priced in GB. In - this case, the conversion factor would be 1024 and the operation would be - "divide". - """ - - quantity_rounding: Optional[QuantityRounding] = None - """Optional. - - Only valid for USAGE products. If provided, the quantity will be rounded using - the provided rounding method and decimal places. For example, if the method is - "round up" and the decimal places is 0, then the quantity will be rounded up to - the nearest integer. - """ - - starting_at: Optional[datetime] = None - - tags: Optional[List[str]] = None - - -class ProductListResponse(BaseModel): - id: str - - current: ProductListItemState - - initial: ProductListItemState - - type: Literal["USAGE", "SUBSCRIPTION", "COMPOSITE", "FIXED", "PRO_SERVICE"] - - updates: List[Update] - - archived_at: Optional[datetime] = None - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" diff --git a/src/metronome/types/v1/contracts/product_retrieve_params.py b/src/metronome/types/v1/contracts/product_retrieve_params.py deleted file mode 100644 index e688feab6..000000000 --- a/src/metronome/types/v1/contracts/product_retrieve_params.py +++ /dev/null @@ -1,11 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["ProductRetrieveParams"] - - -class ProductRetrieveParams(TypedDict, total=False): - id: Required[str] diff --git a/src/metronome/types/v1/contracts/product_retrieve_response.py b/src/metronome/types/v1/contracts/product_retrieve_response.py deleted file mode 100644 index 82793786f..000000000 --- a/src/metronome/types/v1/contracts/product_retrieve_response.py +++ /dev/null @@ -1,99 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from datetime import datetime -from typing_extensions import Literal - -from ...._models import BaseModel -from .quantity_rounding import QuantityRounding -from .quantity_conversion import QuantityConversion -from .product_list_item_state import ProductListItemState - -__all__ = ["ProductRetrieveResponse", "Data", "DataUpdate"] - - -class DataUpdate(BaseModel): - created_at: datetime - - created_by: str - - billable_metric_id: Optional[str] = None - - composite_product_ids: Optional[List[str]] = None - - composite_tags: Optional[List[str]] = None - - exclude_free_usage: Optional[bool] = None - - is_refundable: Optional[bool] = None - - name: Optional[str] = None - - netsuite_internal_item_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - netsuite_overage_item_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - presentation_group_key: Optional[List[str]] = None - """For USAGE products only. - - Groups usage line items on invoices. The superset of values in the pricing group - key and presentation group key must be set as one compound group key on the - billable metric. - """ - - pricing_group_key: Optional[List[str]] = None - """For USAGE products only. - - If set, pricing for this product will be determined for each pricing_group_key - value, as opposed to the product as a whole. The superset of values in the - pricing group key and presentation group key must be set as one compound group - key on the billable metric. - """ - - quantity_conversion: Optional[QuantityConversion] = None - """Optional. - - Only valid for USAGE products. If provided, the quantity will be converted using - the provided conversion factor and operation. For example, if the operation is - "multiply" and the conversion factor is 100, then the quantity will be - multiplied by 100. This can be used in cases where data is sent in one unit and - priced in another. For example, data could be sent in MB and priced in GB. In - this case, the conversion factor would be 1024 and the operation would be - "divide". - """ - - quantity_rounding: Optional[QuantityRounding] = None - """Optional. - - Only valid for USAGE products. If provided, the quantity will be rounded using - the provided rounding method and decimal places. For example, if the method is - "round up" and the decimal places is 0, then the quantity will be rounded up to - the nearest integer. - """ - - starting_at: Optional[datetime] = None - - tags: Optional[List[str]] = None - - -class Data(BaseModel): - id: str - - current: ProductListItemState - - initial: ProductListItemState - - type: Literal["USAGE", "SUBSCRIPTION", "COMPOSITE", "FIXED", "PRO_SERVICE"] - - updates: List[DataUpdate] - - archived_at: Optional[datetime] = None - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - -class ProductRetrieveResponse(BaseModel): - data: Data diff --git a/src/metronome/types/v1/contracts/product_update_params.py b/src/metronome/types/v1/contracts/product_update_params.py deleted file mode 100644 index 7dabd597f..000000000 --- a/src/metronome/types/v1/contracts/product_update_params.py +++ /dev/null @@ -1,113 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Optional -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ...._types import SequenceNotStr -from ...._utils import PropertyInfo -from .quantity_rounding_param import QuantityRoundingParam -from .quantity_conversion_param import QuantityConversionParam - -__all__ = ["ProductUpdateParams"] - - -class ProductUpdateParams(TypedDict, total=False): - product_id: Required[str] - """ID of the product to update""" - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """Timestamp representing when the update should go into effect. - - It must be on an hour boundary (e.g. 1:00, not 1:30). - """ - - billable_metric_id: str - """Available for USAGE products only. - - If not provided, defaults to product's current billable metric. - """ - - composite_product_ids: SequenceNotStr[str] - """Available for COMPOSITE products only. - - If not provided, defaults to product's current composite_product_ids. - """ - - composite_tags: SequenceNotStr[str] - """Available for COMPOSITE products only. - - If not provided, defaults to product's current composite_tags. - """ - - exclude_free_usage: bool - """Beta feature only available for composite products. - - If true, products with $0 will not be included when computing composite usage. - Defaults to false - """ - - is_refundable: bool - """Defaults to product's current refundability status. - - This field's availability is dependent on your client's configuration. - """ - - name: str - """displayed on invoices. If not provided, defaults to product's current name.""" - - netsuite_internal_item_id: str - """If not provided, defaults to product's current netsuite_internal_item_id. - - This field's availability is dependent on your client's configuration. - """ - - netsuite_overage_item_id: str - """Available for USAGE and COMPOSITE products only. - - If not provided, defaults to product's current netsuite_overage_item_id. This - field's availability is dependent on your client's configuration. - """ - - presentation_group_key: SequenceNotStr[str] - """For USAGE products only. - - Groups usage line items on invoices. The superset of values in the pricing group - key and presentation group key must be set as one compound group key on the - billable metric. - """ - - pricing_group_key: SequenceNotStr[str] - """For USAGE products only. - - If set, pricing for this product will be determined for each pricing_group_key - value, as opposed to the product as a whole. The superset of values in the - pricing group key and presentation group key must be set as one compound group - key on the billable metric. - """ - - quantity_conversion: Optional[QuantityConversionParam] - """Optional. - - Only valid for USAGE products. If provided, the quantity will be converted using - the provided conversion factor and operation. For example, if the operation is - "multiply" and the conversion factor is 100, then the quantity will be - multiplied by 100. This can be used in cases where data is sent in one unit and - priced in another. For example, data could be sent in MB and priced in GB. In - this case, the conversion factor would be 1024 and the operation would be - "divide". - """ - - quantity_rounding: Optional[QuantityRoundingParam] - """Optional. - - Only valid for USAGE products. If provided, the quantity will be rounded using - the provided rounding method and decimal places. For example, if the method is - "round up" and the decimal places is 0, then the quantity will be rounded up to - the nearest integer. - """ - - tags: SequenceNotStr[str] - """If not provided, defaults to product's current tags""" diff --git a/src/metronome/types/v1/contracts/product_update_response.py b/src/metronome/types/v1/contracts/product_update_response.py deleted file mode 100644 index 9f65c24a7..000000000 --- a/src/metronome/types/v1/contracts/product_update_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel -from ...shared.id import ID - -__all__ = ["ProductUpdateResponse"] - - -class ProductUpdateResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/contracts/quantity_conversion.py b/src/metronome/types/v1/contracts/quantity_conversion.py deleted file mode 100644 index ea41aa939..000000000 --- a/src/metronome/types/v1/contracts/quantity_conversion.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["QuantityConversion"] - - -class QuantityConversion(BaseModel): - """Optional. - - Only valid for USAGE products. If provided, the quantity will be converted using the provided conversion factor and operation. For example, if the operation is "multiply" and the conversion factor is 100, then the quantity will be multiplied by 100. This can be used in cases where data is sent in one unit and priced in another. For example, data could be sent in MB and priced in GB. In this case, the conversion factor would be 1024 and the operation would be "divide". - """ - - conversion_factor: float - """The factor to multiply or divide the quantity by.""" - - operation: Literal["MULTIPLY", "DIVIDE"] - """The operation to perform on the quantity""" - - name: Optional[str] = None - """Optional name for this conversion.""" diff --git a/src/metronome/types/v1/contracts/quantity_conversion_param.py b/src/metronome/types/v1/contracts/quantity_conversion_param.py deleted file mode 100644 index ca262e5b4..000000000 --- a/src/metronome/types/v1/contracts/quantity_conversion_param.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["QuantityConversionParam"] - - -class QuantityConversionParam(TypedDict, total=False): - """Optional. - - Only valid for USAGE products. If provided, the quantity will be converted using the provided conversion factor and operation. For example, if the operation is "multiply" and the conversion factor is 100, then the quantity will be multiplied by 100. This can be used in cases where data is sent in one unit and priced in another. For example, data could be sent in MB and priced in GB. In this case, the conversion factor would be 1024 and the operation would be "divide". - """ - - conversion_factor: Required[float] - """The factor to multiply or divide the quantity by.""" - - operation: Required[Literal["MULTIPLY", "DIVIDE"]] - """The operation to perform on the quantity""" - - name: str - """Optional name for this conversion.""" diff --git a/src/metronome/types/v1/contracts/quantity_rounding.py b/src/metronome/types/v1/contracts/quantity_rounding.py deleted file mode 100644 index beae87ac9..000000000 --- a/src/metronome/types/v1/contracts/quantity_rounding.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["QuantityRounding"] - - -class QuantityRounding(BaseModel): - """Optional. - - Only valid for USAGE products. If provided, the quantity will be rounded using the provided rounding method and decimal places. For example, if the method is "round up" and the decimal places is 0, then the quantity will be rounded up to the nearest integer. - """ - - decimal_places: float - - rounding_method: Literal["ROUND_UP", "ROUND_DOWN", "ROUND_HALF_UP"] diff --git a/src/metronome/types/v1/contracts/quantity_rounding_param.py b/src/metronome/types/v1/contracts/quantity_rounding_param.py deleted file mode 100644 index cee24f8c8..000000000 --- a/src/metronome/types/v1/contracts/quantity_rounding_param.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["QuantityRoundingParam"] - - -class QuantityRoundingParam(TypedDict, total=False): - """Optional. - - Only valid for USAGE products. If provided, the quantity will be rounded using the provided rounding method and decimal places. For example, if the method is "round up" and the decimal places is 0, then the quantity will be rounded up to the nearest integer. - """ - - decimal_places: Required[float] - - rounding_method: Required[Literal["ROUND_UP", "ROUND_DOWN", "ROUND_HALF_UP"]] diff --git a/src/metronome/types/v1/contracts/rate_card_archive_params.py b/src/metronome/types/v1/contracts/rate_card_archive_params.py deleted file mode 100644 index 7cb9795ce..000000000 --- a/src/metronome/types/v1/contracts/rate_card_archive_params.py +++ /dev/null @@ -1,11 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["RateCardArchiveParams"] - - -class RateCardArchiveParams(TypedDict, total=False): - id: Required[str] diff --git a/src/metronome/types/v1/contracts/rate_card_archive_response.py b/src/metronome/types/v1/contracts/rate_card_archive_response.py deleted file mode 100644 index c4e688a98..000000000 --- a/src/metronome/types/v1/contracts/rate_card_archive_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel -from ...shared.id import ID - -__all__ = ["RateCardArchiveResponse"] - - -class RateCardArchiveResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/contracts/rate_card_create_params.py b/src/metronome/types/v1/contracts/rate_card_create_params.py deleted file mode 100644 index 4866008cd..000000000 --- a/src/metronome/types/v1/contracts/rate_card_create_params.py +++ /dev/null @@ -1,51 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ...._utils import PropertyInfo - -__all__ = ["RateCardCreateParams", "Alias", "CreditTypeConversion"] - - -class RateCardCreateParams(TypedDict, total=False): - name: Required[str] - """Used only in UI/API. It is not exposed to end customers.""" - - aliases: Iterable[Alias] - """Reference this alias when creating a contract. - - If the same alias is assigned to multiple rate cards, it will reference the rate - card to which it was most recently assigned. It is not exposed to end customers. - """ - - credit_type_conversions: Iterable[CreditTypeConversion] - """Required when using custom pricing units in rates.""" - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: str - - fiat_credit_type_id: str - """ - The Metronome ID of the credit type to associate with the rate card, defaults to - USD (cents) if not passed. - """ - - -class Alias(TypedDict, total=False): - name: Required[str] - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - - starting_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - - -class CreditTypeConversion(TypedDict, total=False): - custom_credit_type_id: Required[str] - - fiat_per_custom_credit: Required[float] diff --git a/src/metronome/types/v1/contracts/rate_card_create_response.py b/src/metronome/types/v1/contracts/rate_card_create_response.py deleted file mode 100644 index 741f63d8c..000000000 --- a/src/metronome/types/v1/contracts/rate_card_create_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel -from ...shared.id import ID - -__all__ = ["RateCardCreateResponse"] - - -class RateCardCreateResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/contracts/rate_card_list_params.py b/src/metronome/types/v1/contracts/rate_card_list_params.py deleted file mode 100644 index cae8db35f..000000000 --- a/src/metronome/types/v1/contracts/rate_card_list_params.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["RateCardListParams"] - - -class RateCardListParams(TypedDict, total=False): - limit: int - """Max number of results that should be returned""" - - next_page: str - """Cursor that indicates where the next page of results should start.""" - - body: object diff --git a/src/metronome/types/v1/contracts/rate_card_list_response.py b/src/metronome/types/v1/contracts/rate_card_list_response.py deleted file mode 100644 index e04210335..000000000 --- a/src/metronome/types/v1/contracts/rate_card_list_response.py +++ /dev/null @@ -1,44 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from datetime import datetime - -from ...._models import BaseModel -from ...shared.credit_type_data import CreditTypeData - -__all__ = ["RateCardListResponse", "Alias", "CreditTypeConversion"] - - -class Alias(BaseModel): - name: str - - ending_before: Optional[datetime] = None - - starting_at: Optional[datetime] = None - - -class CreditTypeConversion(BaseModel): - custom_credit_type: CreditTypeData - - fiat_per_custom_credit: str - - -class RateCardListResponse(BaseModel): - id: str - - created_at: datetime - - created_by: str - - name: str - - aliases: Optional[List[Alias]] = None - - credit_type_conversions: Optional[List[CreditTypeConversion]] = None - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: Optional[str] = None - - fiat_credit_type: Optional[CreditTypeData] = None diff --git a/src/metronome/types/v1/contracts/rate_card_retrieve_params.py b/src/metronome/types/v1/contracts/rate_card_retrieve_params.py deleted file mode 100644 index 716e22767..000000000 --- a/src/metronome/types/v1/contracts/rate_card_retrieve_params.py +++ /dev/null @@ -1,11 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["RateCardRetrieveParams"] - - -class RateCardRetrieveParams(TypedDict, total=False): - id: Required[str] diff --git a/src/metronome/types/v1/contracts/rate_card_retrieve_rate_schedule_params.py b/src/metronome/types/v1/contracts/rate_card_retrieve_rate_schedule_params.py deleted file mode 100644 index 5bf4c356d..000000000 --- a/src/metronome/types/v1/contracts/rate_card_retrieve_rate_schedule_params.py +++ /dev/null @@ -1,60 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ...._utils import PropertyInfo - -__all__ = ["RateCardRetrieveRateScheduleParams", "Selector"] - - -class RateCardRetrieveRateScheduleParams(TypedDict, total=False): - rate_card_id: Required[str] - """ID of the rate card to get the schedule for""" - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """inclusive starting point for the rates schedule""" - - limit: int - """Max number of results that should be returned""" - - next_page: str - """Cursor that indicates where the next page of results should start.""" - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """optional exclusive end date for the rates schedule. - - When not specified rates will show all future schedule segments. - """ - - selectors: Iterable[Selector] - """ - List of rate selectors, rates matching ANY of the selector will be included in - the response Passing no selectors will result in all rates being returned. - """ - - -class Selector(TypedDict, total=False): - billing_frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"] - """ - Subscription rates matching the billing frequency will be included in the - response. - """ - - partial_pricing_group_values: Dict[str, str] - """ - List of pricing group key value pairs, rates containing the matching key / value - pairs will be included in the response. - """ - - pricing_group_values: Dict[str, str] - """ - List of pricing group key value pairs, rates matching all of the key / value - pairs will be included in the response. - """ - - product_id: str - """Rates matching the product id will be included in the response.""" diff --git a/src/metronome/types/v1/contracts/rate_card_retrieve_rate_schedule_response.py b/src/metronome/types/v1/contracts/rate_card_retrieve_rate_schedule_response.py deleted file mode 100644 index 6c74fd248..000000000 --- a/src/metronome/types/v1/contracts/rate_card_retrieve_rate_schedule_response.py +++ /dev/null @@ -1,47 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from datetime import datetime -from typing_extensions import Literal - -from ...._models import BaseModel -from ...shared.rate import Rate -from ...shared.commit_rate import CommitRate - -__all__ = ["RateCardRetrieveRateScheduleResponse", "Data"] - - -class Data(BaseModel): - entitled: bool - - product_custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - product_id: str - - product_name: str - - product_tags: List[str] - - rate: Rate - - starting_at: datetime - - billing_frequency: Optional[Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"]] = None - - commit_rate: Optional[CommitRate] = None - """A distinct rate on the rate card. - - You can choose to use this rate rather than list rate when consuming a credit or - commit. - """ - - ending_before: Optional[datetime] = None - - pricing_group_values: Optional[Dict[str, str]] = None - - -class RateCardRetrieveRateScheduleResponse(BaseModel): - data: List[Data] - - next_page: Optional[str] = None diff --git a/src/metronome/types/v1/contracts/rate_card_retrieve_response.py b/src/metronome/types/v1/contracts/rate_card_retrieve_response.py deleted file mode 100644 index ee6a5bb85..000000000 --- a/src/metronome/types/v1/contracts/rate_card_retrieve_response.py +++ /dev/null @@ -1,48 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from datetime import datetime - -from ...._models import BaseModel -from ...shared.credit_type_data import CreditTypeData - -__all__ = ["RateCardRetrieveResponse", "Data", "DataAlias", "DataCreditTypeConversion"] - - -class DataAlias(BaseModel): - name: str - - ending_before: Optional[datetime] = None - - starting_at: Optional[datetime] = None - - -class DataCreditTypeConversion(BaseModel): - custom_credit_type: CreditTypeData - - fiat_per_custom_credit: str - - -class Data(BaseModel): - id: str - - created_at: datetime - - created_by: str - - name: str - - aliases: Optional[List[DataAlias]] = None - - credit_type_conversions: Optional[List[DataCreditTypeConversion]] = None - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: Optional[str] = None - - fiat_credit_type: Optional[CreditTypeData] = None - - -class RateCardRetrieveResponse(BaseModel): - data: Data diff --git a/src/metronome/types/v1/contracts/rate_card_update_params.py b/src/metronome/types/v1/contracts/rate_card_update_params.py deleted file mode 100644 index a83147d18..000000000 --- a/src/metronome/types/v1/contracts/rate_card_update_params.py +++ /dev/null @@ -1,36 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ...._utils import PropertyInfo - -__all__ = ["RateCardUpdateParams", "Alias"] - - -class RateCardUpdateParams(TypedDict, total=False): - rate_card_id: Required[str] - """ID of the rate card to update""" - - aliases: Iterable[Alias] - """Reference this alias when creating a contract. - - If the same alias is assigned to multiple rate cards, it will reference the rate - card to which it was most recently assigned. It is not exposed to end customers. - """ - - description: str - - name: str - """Used only in UI/API. It is not exposed to end customers.""" - - -class Alias(TypedDict, total=False): - name: Required[str] - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - - starting_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] diff --git a/src/metronome/types/v1/contracts/rate_card_update_response.py b/src/metronome/types/v1/contracts/rate_card_update_response.py deleted file mode 100644 index 04d4def68..000000000 --- a/src/metronome/types/v1/contracts/rate_card_update_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel -from ...shared.id import ID - -__all__ = ["RateCardUpdateResponse"] - - -class RateCardUpdateResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/contracts/rate_cards/__init__.py b/src/metronome/types/v1/contracts/rate_cards/__init__.py deleted file mode 100644 index d030c1637..000000000 --- a/src/metronome/types/v1/contracts/rate_cards/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .rate_add_params import RateAddParams as RateAddParams -from .rate_list_params import RateListParams as RateListParams -from .rate_add_response import RateAddResponse as RateAddResponse -from .rate_list_response import RateListResponse as RateListResponse -from .rate_add_many_params import RateAddManyParams as RateAddManyParams -from .rate_add_many_response import RateAddManyResponse as RateAddManyResponse -from .product_order_set_params import ProductOrderSetParams as ProductOrderSetParams -from .product_order_set_response import ProductOrderSetResponse as ProductOrderSetResponse -from .product_order_update_params import ProductOrderUpdateParams as ProductOrderUpdateParams -from .named_schedule_update_params import NamedScheduleUpdateParams as NamedScheduleUpdateParams -from .product_order_update_response import ProductOrderUpdateResponse as ProductOrderUpdateResponse -from .named_schedule_retrieve_params import NamedScheduleRetrieveParams as NamedScheduleRetrieveParams -from .named_schedule_retrieve_response import NamedScheduleRetrieveResponse as NamedScheduleRetrieveResponse diff --git a/src/metronome/types/v1/contracts/rate_cards/named_schedule_retrieve_params.py b/src/metronome/types/v1/contracts/rate_cards/named_schedule_retrieve_params.py deleted file mode 100644 index 16a2bbb46..000000000 --- a/src/metronome/types/v1/contracts/rate_cards/named_schedule_retrieve_params.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ....._utils import PropertyInfo - -__all__ = ["NamedScheduleRetrieveParams"] - - -class NamedScheduleRetrieveParams(TypedDict, total=False): - contract_id: Required[str] - """ID of the contract whose named schedule is to be retrieved""" - - customer_id: Required[str] - """ID of the customer whose named schedule is to be retrieved""" - - schedule_name: Required[str] - """The identifier for the schedule to be retrieved""" - - covering_date: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """ - If provided, at most one schedule segment will be returned (the one that covers - this date). If not provided, all segments will be returned. - """ diff --git a/src/metronome/types/v1/contracts/rate_cards/named_schedule_retrieve_response.py b/src/metronome/types/v1/contracts/rate_cards/named_schedule_retrieve_response.py deleted file mode 100644 index 5339b3222..000000000 --- a/src/metronome/types/v1/contracts/rate_cards/named_schedule_retrieve_response.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime - -from ....._models import BaseModel - -__all__ = ["NamedScheduleRetrieveResponse", "Data"] - - -class Data(BaseModel): - starting_at: datetime - - value: object - - ending_before: Optional[datetime] = None - - -class NamedScheduleRetrieveResponse(BaseModel): - data: List[Data] diff --git a/src/metronome/types/v1/contracts/rate_cards/named_schedule_update_params.py b/src/metronome/types/v1/contracts/rate_cards/named_schedule_update_params.py deleted file mode 100644 index a44e9e435..000000000 --- a/src/metronome/types/v1/contracts/rate_cards/named_schedule_update_params.py +++ /dev/null @@ -1,32 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ....._utils import PropertyInfo - -__all__ = ["NamedScheduleUpdateParams"] - - -class NamedScheduleUpdateParams(TypedDict, total=False): - contract_id: Required[str] - """ID of the contract whose named schedule is to be updated""" - - customer_id: Required[str] - """ID of the customer whose named schedule is to be updated""" - - schedule_name: Required[str] - """The identifier for the schedule to be updated""" - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - value: Required[object] - """The value to set for the named schedule. - - The structure of this object is specific to the named schedule. - """ - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] diff --git a/src/metronome/types/v1/contracts/rate_cards/product_order_set_params.py b/src/metronome/types/v1/contracts/rate_cards/product_order_set_params.py deleted file mode 100644 index f073bd38a..000000000 --- a/src/metronome/types/v1/contracts/rate_cards/product_order_set_params.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -from ....._types import SequenceNotStr - -__all__ = ["ProductOrderSetParams"] - - -class ProductOrderSetParams(TypedDict, total=False): - product_order: Required[SequenceNotStr[str]] - - rate_card_id: Required[str] - """ID of the rate card to update""" diff --git a/src/metronome/types/v1/contracts/rate_cards/product_order_set_response.py b/src/metronome/types/v1/contracts/rate_cards/product_order_set_response.py deleted file mode 100644 index 996671e49..000000000 --- a/src/metronome/types/v1/contracts/rate_cards/product_order_set_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ....._models import BaseModel -from ....shared.id import ID - -__all__ = ["ProductOrderSetResponse"] - - -class ProductOrderSetResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/contracts/rate_cards/product_order_update_params.py b/src/metronome/types/v1/contracts/rate_cards/product_order_update_params.py deleted file mode 100644 index 116e92dcf..000000000 --- a/src/metronome/types/v1/contracts/rate_cards/product_order_update_params.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable -from typing_extensions import Required, TypedDict - -__all__ = ["ProductOrderUpdateParams", "ProductMove"] - - -class ProductOrderUpdateParams(TypedDict, total=False): - product_moves: Required[Iterable[ProductMove]] - - rate_card_id: Required[str] - """ID of the rate card to update""" - - -class ProductMove(TypedDict, total=False): - position: Required[float] - """0-based index of the new position of the product""" - - product_id: Required[str] - """ID of the product to move""" diff --git a/src/metronome/types/v1/contracts/rate_cards/product_order_update_response.py b/src/metronome/types/v1/contracts/rate_cards/product_order_update_response.py deleted file mode 100644 index 184510d79..000000000 --- a/src/metronome/types/v1/contracts/rate_cards/product_order_update_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ....._models import BaseModel -from ....shared.id import ID - -__all__ = ["ProductOrderUpdateResponse"] - - -class ProductOrderUpdateResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/contracts/rate_cards/rate_add_many_params.py b/src/metronome/types/v1/contracts/rate_cards/rate_add_many_params.py deleted file mode 100644 index 331d3a2ed..000000000 --- a/src/metronome/types/v1/contracts/rate_cards/rate_add_many_params.py +++ /dev/null @@ -1,86 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ....._utils import PropertyInfo -from ....shared_params.tier import Tier -from ....shared_params.commit_rate import CommitRate - -__all__ = ["RateAddManyParams", "Rate"] - - -class RateAddManyParams(TypedDict, total=False): - rate_card_id: Required[str] - - rates: Required[Iterable[Rate]] - - -class Rate(TypedDict, total=False): - entitled: Required[bool] - - product_id: Required[str] - """ID of the product to add a rate for""" - - rate_type: Required[Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "TIERED", "TIERED_PERCENTAGE", "CUSTOM"]] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """inclusive effective date""" - - billing_frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"] - """Optional. - - Frequency to bill subscriptions with. Required for subscription type products - with Flat rate. - """ - - commit_rate: CommitRate - """A distinct rate on the rate card. - - You can choose to use this rate rather than list rate when consuming a credit or - commit. - """ - - credit_type_id: str - """ - "The Metronome ID of the credit type to associate with price, defaults to USD - (cents) if not passed. Used by all rate_types except type PERCENTAGE. PERCENTAGE - rates use the credit type of associated rates." - """ - - custom_rate: Dict[str, object] - """Only set for CUSTOM rate_type. - - This field is interpreted by custom rate processors. - """ - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """exclusive end date""" - - is_prorated: bool - """Default proration configuration. - - Only valid for SUBSCRIPTION rate_type. Must be set to true. - """ - - price: float - """Default price. - - For FLAT and SUBSCRIPTION rate_type, this must be >=0. For PERCENTAGE rate_type, - this is a decimal fraction, e.g. use 0.1 for 10%; this must be >=0 and <=1. - """ - - pricing_group_values: Dict[str, str] - """Optional. - - List of pricing group key value pairs which will be used to calculate the price. - """ - - quantity: float - """Default quantity. For SUBSCRIPTION rate_type, this must be >=0.""" - - tiers: Iterable[Tier] - """Only set for TIERED rate_type.""" diff --git a/src/metronome/types/v1/contracts/rate_cards/rate_add_many_response.py b/src/metronome/types/v1/contracts/rate_cards/rate_add_many_response.py deleted file mode 100644 index ebd9a7e35..000000000 --- a/src/metronome/types/v1/contracts/rate_cards/rate_add_many_response.py +++ /dev/null @@ -1,11 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ....._models import BaseModel -from ....shared.id import ID - -__all__ = ["RateAddManyResponse"] - - -class RateAddManyResponse(BaseModel): - data: ID - """The ID of the rate card to which the rates were added.""" diff --git a/src/metronome/types/v1/contracts/rate_cards/rate_add_params.py b/src/metronome/types/v1/contracts/rate_cards/rate_add_params.py deleted file mode 100644 index 16041b15b..000000000 --- a/src/metronome/types/v1/contracts/rate_cards/rate_add_params.py +++ /dev/null @@ -1,83 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ....._utils import PropertyInfo -from ....shared_params.tier import Tier -from ....shared_params.commit_rate import CommitRate - -__all__ = ["RateAddParams"] - - -class RateAddParams(TypedDict, total=False): - entitled: Required[bool] - - product_id: Required[str] - """ID of the product to add a rate for""" - - rate_card_id: Required[str] - """ID of the rate card to update""" - - rate_type: Required[Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "TIERED", "TIERED_PERCENTAGE", "CUSTOM"]] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """inclusive effective date""" - - billing_frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"] - """Optional. - - Frequency to bill subscriptions with. Required for subscription type products - with Flat rate. - """ - - commit_rate: CommitRate - """A distinct rate on the rate card. - - You can choose to use this rate rather than list rate when consuming a credit or - commit. - """ - - credit_type_id: str - """ - The Metronome ID of the credit type to associate with price, defaults to USD - (cents) if not passed. Used by all rate_types except type PERCENTAGE. PERCENTAGE - rates use the credit type of associated rates. - """ - - custom_rate: Dict[str, object] - """Only set for CUSTOM rate_type. - - This field is interpreted by custom rate processors. - """ - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """exclusive end date""" - - is_prorated: bool - """Default proration configuration. - - Only valid for SUBSCRIPTION rate_type. Must be set to true. - """ - - price: float - """Default price. - - For FLAT and SUBSCRIPTION rate_type, this must be >=0. For PERCENTAGE rate_type, - this is a decimal fraction, e.g. use 0.1 for 10%; this must be >=0 and <=1. - """ - - pricing_group_values: Dict[str, str] - """Optional. - - List of pricing group key value pairs which will be used to calculate the price. - """ - - quantity: float - """Default quantity. For SUBSCRIPTION rate_type, this must be >=0.""" - - tiers: Iterable[Tier] - """Only set for TIERED rate_type.""" diff --git a/src/metronome/types/v1/contracts/rate_cards/rate_add_response.py b/src/metronome/types/v1/contracts/rate_cards/rate_add_response.py deleted file mode 100644 index c3cdde912..000000000 --- a/src/metronome/types/v1/contracts/rate_cards/rate_add_response.py +++ /dev/null @@ -1,59 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from typing_extensions import Literal - -from ....._models import BaseModel -from ....shared.tier import Tier -from ....shared.commit_rate import CommitRate -from ....shared.credit_type_data import CreditTypeData - -__all__ = ["RateAddResponse", "Data"] - - -class Data(BaseModel): - rate_type: Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "CUSTOM", "TIERED", "TIERED_PERCENTAGE"] - - commit_rate: Optional[CommitRate] = None - """A distinct rate on the rate card. - - You can choose to use this rate rather than list rate when consuming a credit or - commit. - """ - - credit_type: Optional[CreditTypeData] = None - - custom_rate: Optional[Dict[str, object]] = None - """Only set for CUSTOM rate_type. - - This field is interpreted by custom rate processors. - """ - - is_prorated: Optional[bool] = None - """Default proration configuration. - - Only valid for SUBSCRIPTION rate_type. Must be set to true. - """ - - price: Optional[float] = None - """Default price. - - For FLAT rate_type, this must be >=0. For PERCENTAGE rate_type, this is a - decimal fraction, e.g. use 0.1 for 10%; this must be >=0 and <=1. - """ - - pricing_group_values: Optional[Dict[str, str]] = None - """ - if pricing groups are used, this will contain the values used to calculate the - price - """ - - quantity: Optional[float] = None - """Default quantity. For SUBSCRIPTION rate_type, this must be >=0.""" - - tiers: Optional[List[Tier]] = None - """Only set for TIERED rate_type.""" - - -class RateAddResponse(BaseModel): - data: Data diff --git a/src/metronome/types/v1/contracts/rate_cards/rate_list_params.py b/src/metronome/types/v1/contracts/rate_cards/rate_list_params.py deleted file mode 100644 index 7092eda1c..000000000 --- a/src/metronome/types/v1/contracts/rate_cards/rate_list_params.py +++ /dev/null @@ -1,61 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ....._types import SequenceNotStr -from ....._utils import PropertyInfo - -__all__ = ["RateListParams", "Selector"] - - -class RateListParams(TypedDict, total=False): - at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """inclusive starting point for the rates schedule""" - - rate_card_id: Required[str] - """ID of the rate card to get the schedule for""" - - limit: int - """Max number of results that should be returned""" - - next_page: str - """Cursor that indicates where the next page of results should start.""" - - selectors: Iterable[Selector] - """ - List of rate selectors, rates matching ANY of the selector will be included in - the response Passing no selectors will result in all rates being returned. - """ - - -class Selector(TypedDict, total=False): - billing_frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"] - """ - Subscription rates matching the billing frequency will be included in the - response. - """ - - partial_pricing_group_values: Dict[str, str] - """ - List of pricing group key value pairs, rates containing the matching key / value - pairs will be included in the response. - """ - - pricing_group_values: Dict[str, str] - """ - List of pricing group key value pairs, rates matching all of the key / value - pairs will be included in the response. - """ - - product_id: str - """Rates matching the product id will be included in the response.""" - - product_tags: SequenceNotStr[str] - """ - List of product tags, rates matching any of the tags will be included in the - response. - """ diff --git a/src/metronome/types/v1/contracts/rate_cards/rate_list_response.py b/src/metronome/types/v1/contracts/rate_cards/rate_list_response.py deleted file mode 100644 index 669c9b694..000000000 --- a/src/metronome/types/v1/contracts/rate_cards/rate_list_response.py +++ /dev/null @@ -1,41 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from datetime import datetime -from typing_extensions import Literal - -from ....._models import BaseModel -from ....shared.rate import Rate -from ....shared.commit_rate import CommitRate - -__all__ = ["RateListResponse"] - - -class RateListResponse(BaseModel): - entitled: bool - - product_custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - product_id: str - - product_name: str - - product_tags: List[str] - - rate: Rate - - starting_at: datetime - - billing_frequency: Optional[Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"]] = None - - commit_rate: Optional[CommitRate] = None - """A distinct rate on the rate card. - - You can choose to use this rate rather than list rate when consuming a credit or - commit. - """ - - ending_before: Optional[datetime] = None - - pricing_group_values: Optional[Dict[str, str]] = None diff --git a/src/metronome/types/v1/credit_grant_create_params.py b/src/metronome/types/v1/credit_grant_create_params.py deleted file mode 100644 index 7d183b5ad..000000000 --- a/src/metronome/types/v1/credit_grant_create_params.py +++ /dev/null @@ -1,112 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union -from datetime import datetime -from typing_extensions import Required, Annotated, TypeAlias, TypedDict - -from ..._types import SequenceNotStr -from ..._utils import PropertyInfo -from .rollover_amount_max_amount_param import RolloverAmountMaxAmountParam -from .rollover_amount_max_percentage_param import RolloverAmountMaxPercentageParam - -__all__ = ["CreditGrantCreateParams", "GrantAmount", "PaidAmount", "RolloverSettings", "RolloverSettingsRolloverAmount"] - - -class CreditGrantCreateParams(TypedDict, total=False): - customer_id: Required[str] - """the Metronome ID of the customer""" - - expires_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """ - The credit grant will only apply to usage or charges dated before this timestamp - """ - - grant_amount: Required[GrantAmount] - """the amount of credits granted""" - - name: Required[str] - """the name of the credit grant as it will appear on invoices""" - - paid_amount: Required[PaidAmount] - """the amount paid for this credit grant""" - - priority: Required[float] - - credit_grant_type: str - - custom_fields: Dict[str, str] - """Custom fields to attach to the credit grant.""" - - effective_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """ - The credit grant will only apply to usage or charges dated on or after this - timestamp - """ - - invoice_date: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """The date to issue an invoice for the paid_amount.""" - - product_ids: SequenceNotStr[str] - """The product(s) which these credits will be applied to. - - (If unspecified, the credits will be applied to charges for all products.). The - array ordering specified here will be used to determine the order in which - credits will be applied to invoice line items - """ - - reason: str - - rollover_settings: RolloverSettings - """ - Configure a rollover for this credit grant so if it expires it rolls over a - configured amount to a new credit grant. This feature is currently opt-in only. - Contact Metronome to be added to the beta. - """ - - uniqueness_key: str - """Prevents the creation of duplicates. - - If a request to create a record is made with a previously used uniqueness key, a - new record will not be created and the request will fail with a 409 error. - """ - - -class GrantAmount(TypedDict, total=False): - """the amount of credits granted""" - - amount: Required[float] - - credit_type_id: Required[str] - """the ID of the pricing unit to be used. Defaults to USD (cents) if not passed.""" - - -class PaidAmount(TypedDict, total=False): - """the amount paid for this credit grant""" - - amount: Required[float] - - credit_type_id: Required[str] - """the ID of the pricing unit to be used. Defaults to USD (cents) if not passed.""" - - -RolloverSettingsRolloverAmount: TypeAlias = Union[RolloverAmountMaxPercentageParam, RolloverAmountMaxAmountParam] - - -class RolloverSettings(TypedDict, total=False): - """ - Configure a rollover for this credit grant so if it expires it rolls over a configured amount to a new credit grant. This feature is currently opt-in only. Contact Metronome to be added to the beta. - """ - - expires_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """The date to expire the rollover credits.""" - - priority: Required[float] - """ - The priority to give the rollover credit grant that gets created when a rollover - happens. - """ - - rollover_amount: Required[RolloverSettingsRolloverAmount] - """Specify how much to rollover to the rollover credit grant""" diff --git a/src/metronome/types/v1/credit_grant_create_response.py b/src/metronome/types/v1/credit_grant_create_response.py deleted file mode 100644 index d3e7a9a0d..000000000 --- a/src/metronome/types/v1/credit_grant_create_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel -from ..shared.id import ID - -__all__ = ["CreditGrantCreateResponse"] - - -class CreditGrantCreateResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/credit_grant_edit_params.py b/src/metronome/types/v1/credit_grant_edit_params.py deleted file mode 100644 index 94ced31be..000000000 --- a/src/metronome/types/v1/credit_grant_edit_params.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ..._utils import PropertyInfo - -__all__ = ["CreditGrantEditParams"] - - -class CreditGrantEditParams(TypedDict, total=False): - id: Required[str] - """the ID of the credit grant""" - - credit_grant_type: str - """the updated credit grant type""" - - expires_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """the updated expiration date for the credit grant""" - - name: str - """the updated name for the credit grant""" diff --git a/src/metronome/types/v1/credit_grant_edit_response.py b/src/metronome/types/v1/credit_grant_edit_response.py deleted file mode 100644 index 90868f5dc..000000000 --- a/src/metronome/types/v1/credit_grant_edit_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel -from ..shared.id import ID - -__all__ = ["CreditGrantEditResponse"] - - -class CreditGrantEditResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/credit_grant_list_entries_params.py b/src/metronome/types/v1/credit_grant_list_entries_params.py deleted file mode 100644 index 93818dc8c..000000000 --- a/src/metronome/types/v1/credit_grant_list_entries_params.py +++ /dev/null @@ -1,46 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Literal, Annotated, TypedDict - -from ..._types import SequenceNotStr -from ..._utils import PropertyInfo - -__all__ = ["CreditGrantListEntriesParams"] - - -class CreditGrantListEntriesParams(TypedDict, total=False): - next_page: str - """Cursor that indicates where the next page of results should start.""" - - sort: Literal["asc", "desc"] - """Ledgers sort order by date, asc or desc. Defaults to asc.""" - - credit_type_ids: SequenceNotStr[str] - """A list of Metronome credit type IDs to fetch ledger entries for. - - If absent, ledger entries for all credit types will be returned. - """ - - customer_ids: SequenceNotStr[str] - """A list of Metronome customer IDs to fetch ledger entries for. - - If absent, ledger entries for all customers will be returned. - """ - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """ - If supplied, ledger entries will only be returned with an effective_at before - this time. This timestamp must not be in the future. If no timestamp is - supplied, all entries up to the start of the customer's next billing period will - be returned. - """ - - starting_on: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """ - If supplied, only ledger entries effective at or after this time will be - returned. - """ diff --git a/src/metronome/types/v1/credit_grant_list_entries_response.py b/src/metronome/types/v1/credit_grant_list_entries_response.py deleted file mode 100644 index 4b521d0b5..000000000 --- a/src/metronome/types/v1/credit_grant_list_entries_response.py +++ /dev/null @@ -1,72 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List -from datetime import datetime - -from ..._models import BaseModel -from .credit_ledger_entry import CreditLedgerEntry -from ..shared.credit_type_data import CreditTypeData - -__all__ = ["CreditGrantListEntriesResponse", "Ledger", "LedgerEndingBalance", "LedgerStartingBalance"] - - -class LedgerEndingBalance(BaseModel): - """the effective balances at the end of the specified time window""" - - effective_at: datetime - """ - the ending_before request parameter (if supplied) or the current billing - period's end date - """ - - excluding_pending: float - """ - the ending balance, including the balance of all grants that have not expired - before the effective_at date and deductions that happened before the - effective_at date - """ - - including_pending: float - """ - the excluding_pending balance plus any pending invoice deductions and - expirations that will happen by the effective_at date - """ - - -class LedgerStartingBalance(BaseModel): - effective_at: datetime - """ - the starting_on request parameter (if supplied) or the first credit grant's - effective_at date - """ - - excluding_pending: float - """ - the starting balance, including all posted grants, deductions, and expirations - that happened at or before the effective_at timestamp - """ - - including_pending: float - """ - the excluding_pending balance plus any pending activity that has not been posted - at the time of the query - """ - - -class Ledger(BaseModel): - credit_type: CreditTypeData - - ending_balance: LedgerEndingBalance - """the effective balances at the end of the specified time window""" - - entries: List[CreditLedgerEntry] - - pending_entries: List[CreditLedgerEntry] - - starting_balance: LedgerStartingBalance - - -class CreditGrantListEntriesResponse(BaseModel): - customer_id: str - - ledgers: List[Ledger] diff --git a/src/metronome/types/v1/credit_grant_list_params.py b/src/metronome/types/v1/credit_grant_list_params.py deleted file mode 100644 index 5d09c53da..000000000 --- a/src/metronome/types/v1/credit_grant_list_params.py +++ /dev/null @@ -1,44 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Annotated, TypedDict - -from ..._types import SequenceNotStr -from ..._utils import PropertyInfo - -__all__ = ["CreditGrantListParams"] - - -class CreditGrantListParams(TypedDict, total=False): - limit: int - """Max number of results that should be returned""" - - next_page: str - """Cursor that indicates where the next page of results should start.""" - - credit_grant_ids: SequenceNotStr[str] - """An array of credit grant IDs. - - If this is specified, neither credit_type_ids nor customer_ids may be specified. - """ - - credit_type_ids: SequenceNotStr[str] - """An array of credit type IDs. - - This must not be specified if credit_grant_ids is specified. - """ - - customer_ids: SequenceNotStr[str] - """An array of Metronome customer IDs. - - This must not be specified if credit_grant_ids is specified. - """ - - effective_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Only return credit grants that are effective before this timestamp (exclusive).""" - - not_expiring_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Only return credit grants that expire at or after this timestamp.""" diff --git a/src/metronome/types/v1/credit_grant_list_response.py b/src/metronome/types/v1/credit_grant_list_response.py deleted file mode 100644 index 41a20d477..000000000 --- a/src/metronome/types/v1/credit_grant_list_response.py +++ /dev/null @@ -1,115 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from datetime import datetime - -from ..._models import BaseModel -from .credit_ledger_entry import CreditLedgerEntry -from ..shared.credit_type_data import CreditTypeData - -__all__ = ["CreditGrantListResponse", "Balance", "GrantAmount", "PaidAmount", "Product"] - - -class Balance(BaseModel): - """ - The effective balance of the grant as of the end of the customer's current billing period. Expiration deductions will be included only if the grant expires before the end of the current billing period. - """ - - effective_at: datetime - """The end_date of the customer's current billing period.""" - - excluding_pending: float - """The grant's current balance including all posted deductions. - - If the grant has expired, this amount will be 0. - """ - - including_pending: float - """The grant's current balance including all posted and pending deductions. - - If the grant expires before the end of the customer's current billing period, - this amount will be 0. - """ - - -class GrantAmount(BaseModel): - """the amount of credits initially granted""" - - amount: float - - credit_type: CreditTypeData - """the credit type for the amount granted""" - - -class PaidAmount(BaseModel): - """the amount paid for this credit grant""" - - amount: float - - credit_type: CreditTypeData - """the credit type for the amount paid""" - - -class Product(BaseModel): - id: str - - name: str - - -class CreditGrantListResponse(BaseModel): - id: str - """the Metronome ID of the credit grant""" - - balance: Balance - """ - The effective balance of the grant as of the end of the customer's current - billing period. Expiration deductions will be included only if the grant expires - before the end of the current billing period. - """ - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - customer_id: str - """the Metronome ID of the customer""" - - deductions: List[CreditLedgerEntry] - - effective_at: datetime - - expires_at: datetime - - grant_amount: GrantAmount - """the amount of credits initially granted""" - - name: str - - paid_amount: PaidAmount - """the amount paid for this credit grant""" - - pending_deductions: List[CreditLedgerEntry] - - priority: float - - credit_grant_type: Optional[str] = None - - invoice_id: Optional[str] = None - """ - the Metronome ID of the invoice with the purchase charge for this credit grant, - if applicable - """ - - products: Optional[List[Product]] = None - """The products which these credits will be applied to. - - (If unspecified, the credits will be applied to charges for all products.) - """ - - reason: Optional[str] = None - - uniqueness_key: Optional[str] = None - """Prevents the creation of duplicates. - - If a request to create a record is made with a previously used uniqueness key, a - new record will not be created and the request will fail with a 409 error. - """ diff --git a/src/metronome/types/v1/credit_grant_void_params.py b/src/metronome/types/v1/credit_grant_void_params.py deleted file mode 100644 index e8fe0c611..000000000 --- a/src/metronome/types/v1/credit_grant_void_params.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["CreditGrantVoidParams"] - - -class CreditGrantVoidParams(TypedDict, total=False): - id: Required[str] - - release_uniqueness_key: bool - """If true, resets the uniqueness key on this grant so it can be re-used""" - - void_credit_purchase_invoice: bool - """If true, void the purchase invoice associated with the grant""" diff --git a/src/metronome/types/v1/credit_grant_void_response.py b/src/metronome/types/v1/credit_grant_void_response.py deleted file mode 100644 index f01071c15..000000000 --- a/src/metronome/types/v1/credit_grant_void_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel -from ..shared.id import ID - -__all__ = ["CreditGrantVoidResponse"] - - -class CreditGrantVoidResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/credit_ledger_entry.py b/src/metronome/types/v1/credit_ledger_entry.py deleted file mode 100644 index 84f8cd8fc..000000000 --- a/src/metronome/types/v1/credit_ledger_entry.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime - -from ..._models import BaseModel - -__all__ = ["CreditLedgerEntry"] - - -class CreditLedgerEntry(BaseModel): - amount: float - """an amount representing the change to the customer's credit balance""" - - created_by: str - - credit_grant_id: str - """the credit grant this entry is related to""" - - effective_at: datetime - - reason: str - - running_balance: float - """ - the running balance for this credit type at the time of the ledger entry, - including all preceding charges - """ - - invoice_id: Optional[str] = None - """ - if this entry is a deduction, the Metronome ID of the invoice where the credit - deduction was consumed; if this entry is a grant, the Metronome ID of the - invoice where the grant's paid_amount was charged - """ diff --git a/src/metronome/types/v1/custom_field_add_key_params.py b/src/metronome/types/v1/custom_field_add_key_params.py deleted file mode 100644 index 33c76bf4d..000000000 --- a/src/metronome/types/v1/custom_field_add_key_params.py +++ /dev/null @@ -1,40 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["CustomFieldAddKeyParams"] - - -class CustomFieldAddKeyParams(TypedDict, total=False): - enforce_uniqueness: Required[bool] - - entity: Required[ - Literal[ - "alert", - "billable_metric", - "charge", - "commit", - "contract_credit", - "contract_product", - "contract", - "credit_grant", - "customer_plan", - "customer", - "discount", - "invoice", - "plan", - "professional_service", - "product", - "rate_card", - "scheduled_charge", - "subscription", - "package_commit", - "package_credit", - "package_subscription", - "package_scheduled_charge", - ] - ] - - key: Required[str] diff --git a/src/metronome/types/v1/custom_field_delete_values_params.py b/src/metronome/types/v1/custom_field_delete_values_params.py deleted file mode 100644 index 2111874f0..000000000 --- a/src/metronome/types/v1/custom_field_delete_values_params.py +++ /dev/null @@ -1,42 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -from ..._types import SequenceNotStr - -__all__ = ["CustomFieldDeleteValuesParams"] - - -class CustomFieldDeleteValuesParams(TypedDict, total=False): - entity: Required[ - Literal[ - "alert", - "billable_metric", - "charge", - "commit", - "contract_credit", - "contract_product", - "contract", - "credit_grant", - "customer_plan", - "customer", - "discount", - "invoice", - "plan", - "professional_service", - "product", - "rate_card", - "scheduled_charge", - "subscription", - "package_commit", - "package_credit", - "package_subscription", - "package_scheduled_charge", - ] - ] - - entity_id: Required[str] - - keys: Required[SequenceNotStr[str]] diff --git a/src/metronome/types/v1/custom_field_list_keys_params.py b/src/metronome/types/v1/custom_field_list_keys_params.py deleted file mode 100644 index 0f5858ad1..000000000 --- a/src/metronome/types/v1/custom_field_list_keys_params.py +++ /dev/null @@ -1,41 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List -from typing_extensions import Literal, TypedDict - -__all__ = ["CustomFieldListKeysParams"] - - -class CustomFieldListKeysParams(TypedDict, total=False): - next_page: str - """Cursor that indicates where the next page of results should start.""" - - entities: List[ - Literal[ - "alert", - "billable_metric", - "charge", - "commit", - "contract_credit", - "contract_product", - "contract", - "credit_grant", - "customer_plan", - "customer", - "discount", - "invoice", - "plan", - "professional_service", - "product", - "rate_card", - "scheduled_charge", - "subscription", - "package_commit", - "package_credit", - "package_subscription", - "package_scheduled_charge", - ] - ] - """Optional list of entity types to return keys for""" diff --git a/src/metronome/types/v1/custom_field_list_keys_response.py b/src/metronome/types/v1/custom_field_list_keys_response.py deleted file mode 100644 index f18ec633f..000000000 --- a/src/metronome/types/v1/custom_field_list_keys_response.py +++ /dev/null @@ -1,38 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["CustomFieldListKeysResponse"] - - -class CustomFieldListKeysResponse(BaseModel): - enforce_uniqueness: bool - - entity: Literal[ - "alert", - "billable_metric", - "charge", - "commit", - "contract_credit", - "contract_product", - "contract", - "credit_grant", - "customer_plan", - "customer", - "discount", - "invoice", - "plan", - "professional_service", - "product", - "rate_card", - "scheduled_charge", - "subscription", - "package_commit", - "package_credit", - "package_subscription", - "package_scheduled_charge", - ] - - key: str diff --git a/src/metronome/types/v1/custom_field_remove_key_params.py b/src/metronome/types/v1/custom_field_remove_key_params.py deleted file mode 100644 index a872efcd9..000000000 --- a/src/metronome/types/v1/custom_field_remove_key_params.py +++ /dev/null @@ -1,38 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["CustomFieldRemoveKeyParams"] - - -class CustomFieldRemoveKeyParams(TypedDict, total=False): - entity: Required[ - Literal[ - "alert", - "billable_metric", - "charge", - "commit", - "contract_credit", - "contract_product", - "contract", - "credit_grant", - "customer_plan", - "customer", - "discount", - "invoice", - "plan", - "professional_service", - "product", - "rate_card", - "scheduled_charge", - "subscription", - "package_commit", - "package_credit", - "package_subscription", - "package_scheduled_charge", - ] - ] - - key: Required[str] diff --git a/src/metronome/types/v1/custom_field_set_values_params.py b/src/metronome/types/v1/custom_field_set_values_params.py deleted file mode 100644 index df42adef1..000000000 --- a/src/metronome/types/v1/custom_field_set_values_params.py +++ /dev/null @@ -1,42 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["CustomFieldSetValuesParams"] - - -class CustomFieldSetValuesParams(TypedDict, total=False): - custom_fields: Required[Dict[str, str]] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - entity: Required[ - Literal[ - "alert", - "billable_metric", - "charge", - "commit", - "contract_credit", - "contract_product", - "contract", - "credit_grant", - "customer_plan", - "customer", - "discount", - "invoice", - "plan", - "professional_service", - "product", - "rate_card", - "scheduled_charge", - "subscription", - "package_commit", - "package_credit", - "package_subscription", - "package_scheduled_charge", - ] - ] - - entity_id: Required[str] diff --git a/src/metronome/types/v1/customer.py b/src/metronome/types/v1/customer.py deleted file mode 100644 index 4c500a9c4..000000000 --- a/src/metronome/types/v1/customer.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional - -from ..._models import BaseModel - -__all__ = ["Customer"] - - -class Customer(BaseModel): - id: str - """the Metronome ID of the customer""" - - external_id: str - """ - (deprecated, use ingest_aliases instead) the first ID (Metronome or ingest - alias) that can be used in usage events - """ - - ingest_aliases: List[str] - """ - aliases for this customer that can be used instead of the Metronome customer ID - in usage events - """ - - name: str - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" diff --git a/src/metronome/types/v1/customer_archive_billing_configurations_params.py b/src/metronome/types/v1/customer_archive_billing_configurations_params.py deleted file mode 100644 index 7588996ca..000000000 --- a/src/metronome/types/v1/customer_archive_billing_configurations_params.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -from ..._types import SequenceNotStr - -__all__ = ["CustomerArchiveBillingConfigurationsParams"] - - -class CustomerArchiveBillingConfigurationsParams(TypedDict, total=False): - customer_billing_provider_configuration_ids: Required[SequenceNotStr[str]] - """Array of billing provider configuration IDs to archive""" - - customer_id: Required[str] - """The customer ID the billing provider configurations belong to""" diff --git a/src/metronome/types/v1/customer_archive_billing_configurations_response.py b/src/metronome/types/v1/customer_archive_billing_configurations_response.py deleted file mode 100644 index af7c1caf4..000000000 --- a/src/metronome/types/v1/customer_archive_billing_configurations_response.py +++ /dev/null @@ -1,19 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List - -from ..._models import BaseModel - -__all__ = ["CustomerArchiveBillingConfigurationsResponse", "Data"] - - -class Data(BaseModel): - customer_billing_provider_configuration_ids: List[str] - """Array of billing provider configuration IDs to archive""" - - customer_id: str - """The customer ID the billing provider configurations belong to""" - - -class CustomerArchiveBillingConfigurationsResponse(BaseModel): - data: Data diff --git a/src/metronome/types/v1/customer_archive_params.py b/src/metronome/types/v1/customer_archive_params.py deleted file mode 100644 index 341450821..000000000 --- a/src/metronome/types/v1/customer_archive_params.py +++ /dev/null @@ -1,11 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["CustomerArchiveParams"] - - -class CustomerArchiveParams(TypedDict, total=False): - id: Required[str] diff --git a/src/metronome/types/v1/customer_archive_response.py b/src/metronome/types/v1/customer_archive_response.py deleted file mode 100644 index 0c3d80a3b..000000000 --- a/src/metronome/types/v1/customer_archive_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel -from ..shared.id import ID - -__all__ = ["CustomerArchiveResponse"] - - -class CustomerArchiveResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/customer_create_params.py b/src/metronome/types/v1/customer_create_params.py deleted file mode 100644 index af93995b8..000000000 --- a/src/metronome/types/v1/customer_create_params.py +++ /dev/null @@ -1,158 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Iterable -from typing_extensions import Literal, Required, TypedDict - -from ..._types import SequenceNotStr - -__all__ = [ - "CustomerCreateParams", - "BillingConfig", - "CustomerBillingProviderConfiguration", - "CustomerRevenueSystemConfiguration", -] - - -class CustomerCreateParams(TypedDict, total=False): - name: Required[str] - """This will be truncated to 160 characters if the provided name is longer.""" - - billing_config: BillingConfig - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - customer_billing_provider_configurations: Iterable[CustomerBillingProviderConfiguration] - - customer_revenue_system_configurations: Iterable[CustomerRevenueSystemConfiguration] - - external_id: str - """ - (deprecated, use ingest_aliases instead) an alias that can be used to refer to - this customer in usage events - """ - - ingest_aliases: SequenceNotStr[str] - """Aliases that can be used to refer to this customer in usage events""" - - -class BillingConfig(TypedDict, total=False): - billing_provider_customer_id: Required[str] - - billing_provider_type: Required[ - Literal[ - "aws_marketplace", - "stripe", - "netsuite", - "custom", - "azure_marketplace", - "quickbooks_online", - "workday", - "gcp_marketplace", - "metronome", - ] - ] - - aws_customer_account_id: str - - aws_customer_id: str - - aws_is_subscription_product: bool - """True if the aws_product_code is a SAAS subscription product, false otherwise.""" - - aws_product_code: str - - aws_region: Literal[ - "af-south-1", - "ap-east-1", - "ap-northeast-1", - "ap-northeast-2", - "ap-northeast-3", - "ap-south-1", - "ap-southeast-1", - "ap-southeast-2", - "ca-central-1", - "cn-north-1", - "cn-northwest-1", - "eu-central-1", - "eu-north-1", - "eu-south-1", - "eu-west-1", - "eu-west-2", - "eu-west-3", - "me-south-1", - "sa-east-1", - "us-east-1", - "us-east-2", - "us-gov-east-1", - "us-gov-west-1", - "us-west-1", - "us-west-2", - ] - - stripe_collection_method: Literal[ - "charge_automatically", "send_invoice", "auto_charge_payment_intent", "manually_charge_payment_intent" - ] - """ - The collection method for the customer's invoices. NOTE: - `auto_charge_payment_intent` and `manually_charge_payment_intent` are in beta. - """ - - -class CustomerBillingProviderConfiguration(TypedDict, total=False): - billing_provider: Required[Literal["aws_marketplace", "azure_marketplace", "gcp_marketplace", "stripe", "netsuite"]] - """The billing provider set for this configuration.""" - - configuration: Dict[str, object] - """Configuration for the billing provider. - - The structure of this object is specific to the billing provider and delivery - provider combination. Defaults to an empty object, however, for most billing - provider + delivery method combinations, it will not be a valid configuration. - """ - - delivery_method: Literal["direct_to_billing_provider", "aws_sqs", "tackle", "aws_sns"] - """The method to use for delivering invoices to this customer. - - If not provided, the `delivery_method_id` must be provided. - """ - - delivery_method_id: str - """ID of the delivery method to use for this customer. - - If not provided, the `delivery_method` must be provided. - """ - - tax_provider: Literal["anrok", "avalara", "stripe"] - """ - Specifies which tax provider Metronome should use for tax calculation when - billing through Stripe. This is only supported for Stripe billing provider - configurations with auto_charge_payment_intent or manual_charge_payment_intent - collection methods. - """ - - -class CustomerRevenueSystemConfiguration(TypedDict, total=False): - provider: Required[Literal["netsuite"]] - """The revenue system provider set for this configuration.""" - - configuration: Dict[str, object] - """Configuration for the revenue system provider. - - The structure of this object is specific to the revenue system provider. For - NetSuite, this should contain `netsuite_customer_id`. - """ - - delivery_method: Literal["direct_to_billing_provider"] - """The method to use for delivering invoices to this customer. - - If not provided, the `delivery_method_id` must be provided. - """ - - delivery_method_id: str - """ID of the delivery method to use for this customer. - - If not provided, the `delivery_method` must be provided. - """ diff --git a/src/metronome/types/v1/customer_create_response.py b/src/metronome/types/v1/customer_create_response.py deleted file mode 100644 index 6bbc18f56..000000000 --- a/src/metronome/types/v1/customer_create_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .customer import Customer -from ..._models import BaseModel - -__all__ = ["CustomerCreateResponse"] - - -class CustomerCreateResponse(BaseModel): - data: Customer diff --git a/src/metronome/types/v1/customer_detail.py b/src/metronome/types/v1/customer_detail.py deleted file mode 100644 index 3c56dd935..000000000 --- a/src/metronome/types/v1/customer_detail.py +++ /dev/null @@ -1,61 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from datetime import datetime -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["CustomerDetail", "CustomerConfig", "CurrentBillableStatus"] - - -class CustomerConfig(BaseModel): - salesforce_account_id: Optional[str] = None - """The Salesforce account ID for the customer""" - - -class CurrentBillableStatus(BaseModel): - """This field's availability is dependent on your client's configuration.""" - - value: Literal["billable", "unbillable"] - - effective_at: Optional[datetime] = None - - -class CustomerDetail(BaseModel): - id: str - """the Metronome ID of the customer""" - - created_at: datetime - """RFC 3339 timestamp indicating when the customer was created.""" - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - customer_config: CustomerConfig - - external_id: str - """ - (deprecated, use ingest_aliases instead) the first ID (Metronome or ingest - alias) that can be used in usage events - """ - - ingest_aliases: List[str] - """ - aliases for this customer that can be used instead of the Metronome customer ID - in usage events - """ - - name: str - - updated_at: datetime - """RFC 3339 timestamp indicating when the customer was last updated.""" - - archived_at: Optional[datetime] = None - """RFC 3339 timestamp indicating when the customer was archived. - - Null if the customer is active. - """ - - current_billable_status: Optional[CurrentBillableStatus] = None - """This field's availability is dependent on your client's configuration.""" diff --git a/src/metronome/types/v1/customer_list_billable_metrics_params.py b/src/metronome/types/v1/customer_list_billable_metrics_params.py deleted file mode 100644 index 1b1e22f63..000000000 --- a/src/metronome/types/v1/customer_list_billable_metrics_params.py +++ /dev/null @@ -1,26 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["CustomerListBillableMetricsParams"] - - -class CustomerListBillableMetricsParams(TypedDict, total=False): - customer_id: Required[str] - - include_archived: bool - """If true, the list of returned metrics will include archived metrics""" - - limit: int - """Max number of results that should be returned""" - - next_page: str - """Cursor that indicates where the next page of results should start.""" - - on_current_plan: bool - """ - If true, the list of metrics will be filtered to just ones that are on the - customer's current plan - """ diff --git a/src/metronome/types/v1/customer_list_billable_metrics_response.py b/src/metronome/types/v1/customer_list_billable_metrics_response.py deleted file mode 100644 index 91e6a35d7..000000000 --- a/src/metronome/types/v1/customer_list_billable_metrics_response.py +++ /dev/null @@ -1,68 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from datetime import datetime -from typing_extensions import Literal - -from ..._models import BaseModel -from ..shared.property_filter import PropertyFilter -from ..shared.event_type_filter import EventTypeFilter - -__all__ = ["CustomerListBillableMetricsResponse"] - - -class CustomerListBillableMetricsResponse(BaseModel): - id: str - - name: str - - aggregate: Optional[str] = None - """(DEPRECATED) use aggregation_type instead""" - - aggregate_keys: Optional[List[str]] = None - """(DEPRECATED) use aggregation_key instead""" - - aggregation_key: Optional[str] = None - """A key that specifies which property of the event is used to aggregate data. - - This key must be one of the property filter names and is not applicable when the - aggregation type is 'count'. - """ - - aggregation_type: Optional[Literal["COUNT", "LATEST", "MAX", "SUM", "UNIQUE"]] = None - """Specifies the type of aggregation performed on matching events.""" - - archived_at: Optional[datetime] = None - """RFC 3339 timestamp indicating when the billable metric was archived. - - If not provided, the billable metric is not archived. - """ - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - event_type_filter: Optional[EventTypeFilter] = None - """An optional filtering rule to match the 'event_type' property of an event.""" - - filter: Optional[Dict[str, object]] = None - """(DEPRECATED) use property_filters & event_type_filter instead""" - - group_by: Optional[List[str]] = None - """(DEPRECATED) use group_keys instead""" - - group_keys: Optional[List[List[str]]] = None - """Property names that are used to group usage costs on an invoice. - - Each entry represents a set of properties used to slice events into distinct - buckets. - """ - - property_filters: Optional[List[PropertyFilter]] = None - """A list of filters to match events to this billable metric. - - Each filter defines a rule on an event property. All rules must pass for the - event to match the billable metric. - """ - - sql: Optional[str] = None - """The SQL query associated with the billable metric""" diff --git a/src/metronome/types/v1/customer_list_costs_params.py b/src/metronome/types/v1/customer_list_costs_params.py deleted file mode 100644 index 1ad398064..000000000 --- a/src/metronome/types/v1/customer_list_costs_params.py +++ /dev/null @@ -1,27 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ..._utils import PropertyInfo - -__all__ = ["CustomerListCostsParams"] - - -class CustomerListCostsParams(TypedDict, total=False): - customer_id: Required[str] - - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (exclusive)""" - - starting_on: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (inclusive)""" - - limit: int - """Max number of results that should be returned""" - - next_page: str - """Cursor that indicates where the next page of results should start.""" diff --git a/src/metronome/types/v1/customer_list_costs_response.py b/src/metronome/types/v1/customer_list_costs_response.py deleted file mode 100644 index 4006565df..000000000 --- a/src/metronome/types/v1/customer_list_costs_response.py +++ /dev/null @@ -1,34 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from datetime import datetime - -from ..._models import BaseModel - -__all__ = ["CustomerListCostsResponse", "CreditTypes", "CreditTypesLineItemBreakdown"] - - -class CreditTypesLineItemBreakdown(BaseModel): - cost: float - - name: str - - group_key: Optional[str] = None - - group_value: Optional[str] = None - - -class CreditTypes(BaseModel): - cost: Optional[float] = None - - line_item_breakdown: Optional[List[CreditTypesLineItemBreakdown]] = None - - name: Optional[str] = None - - -class CustomerListCostsResponse(BaseModel): - credit_types: Dict[str, CreditTypes] - - end_timestamp: datetime - - start_timestamp: datetime diff --git a/src/metronome/types/v1/customer_list_params.py b/src/metronome/types/v1/customer_list_params.py deleted file mode 100644 index f296f4a3b..000000000 --- a/src/metronome/types/v1/customer_list_params.py +++ /dev/null @@ -1,35 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -from ..._types import SequenceNotStr - -__all__ = ["CustomerListParams"] - - -class CustomerListParams(TypedDict, total=False): - customer_ids: SequenceNotStr[str] - """Filter the customer list by customer_id. Up to 100 ids can be provided.""" - - ingest_alias: str - """Filter the customer list by ingest_alias""" - - limit: int - """Max number of results that should be returned""" - - next_page: str - """Cursor that indicates where the next page of results should start.""" - - only_archived: bool - """Filter the customer list to only return archived customers. - - By default, only active customers are returned. - """ - - salesforce_account_ids: SequenceNotStr[str] - """Filter the customer list by salesforce_account_id. - - Up to 100 ids can be provided. - """ diff --git a/src/metronome/types/v1/customer_preview_events_params.py b/src/metronome/types/v1/customer_preview_events_params.py deleted file mode 100644 index 20894ce80..000000000 --- a/src/metronome/types/v1/customer_preview_events_params.py +++ /dev/null @@ -1,46 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Iterable -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["CustomerPreviewEventsParams", "Event"] - - -class CustomerPreviewEventsParams(TypedDict, total=False): - customer_id: Required[str] - - events: Required[Iterable[Event]] - """Array of usage events to include in the preview calculation. - - Must contain at least one event in `merge` mode. - """ - - mode: Literal["replace", "merge"] - """Controls how the provided events are combined with existing usage data. - - Use `replace` to calculate the preview as if these are the only events for the - customer, ignoring all historical usage. Use `merge` to combine these events - with the customer's existing usage. Defaults to `replace`. - """ - - skip_zero_qty_line_items: bool - """When `true`, line items with zero quantity are excluded from the response.""" - - -class Event(TypedDict, total=False): - event_type: Required[str] - - properties: Dict[str, object] - - timestamp: str - """RFC 3339 formatted. If not provided, the current time will be used.""" - - transaction_id: str - """Optional unique identifier for event deduplication. - - When provided, preview events are automatically deduplicated against historical - events from the past 34 days. Duplicate transaction IDs within the same request - will return an error. - """ diff --git a/src/metronome/types/v1/customer_preview_events_response.py b/src/metronome/types/v1/customer_preview_events_response.py deleted file mode 100644 index 8159cd490..000000000 --- a/src/metronome/types/v1/customer_preview_events_response.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List - -from ..._models import BaseModel -from .customers.invoice import Invoice - -__all__ = ["CustomerPreviewEventsResponse"] - - -class CustomerPreviewEventsResponse(BaseModel): - data: List[Invoice] diff --git a/src/metronome/types/v1/customer_retrieve_billing_configurations_params.py b/src/metronome/types/v1/customer_retrieve_billing_configurations_params.py deleted file mode 100644 index d250847b3..000000000 --- a/src/metronome/types/v1/customer_retrieve_billing_configurations_params.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["CustomerRetrieveBillingConfigurationsParams"] - - -class CustomerRetrieveBillingConfigurationsParams(TypedDict, total=False): - customer_id: Required[str] - - include_archived: bool diff --git a/src/metronome/types/v1/customer_retrieve_billing_configurations_response.py b/src/metronome/types/v1/customer_retrieve_billing_configurations_response.py deleted file mode 100644 index c9000cc7f..000000000 --- a/src/metronome/types/v1/customer_retrieve_billing_configurations_response.py +++ /dev/null @@ -1,56 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from datetime import datetime -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["CustomerRetrieveBillingConfigurationsResponse", "Data"] - - -class Data(BaseModel): - id: str - """ - ID of this configuration; can be provided as the - billing_provider_configuration_id when creating a contract. - """ - - archived_at: Optional[datetime] = None - - billing_provider: Literal[ - "aws_marketplace", - "stripe", - "netsuite", - "custom", - "azure_marketplace", - "quickbooks_online", - "workday", - "gcp_marketplace", - "metronome", - ] - """The billing provider set for this configuration.""" - - configuration: Dict[str, object] - """Configuration for the billing provider. - - The structure of this object is specific to the billing provider. - """ - - customer_id: str - - delivery_method: Literal["direct_to_billing_provider", "aws_sqs", "tackle", "aws_sns"] - """The method to use for delivering invoices to this customer.""" - - delivery_method_configuration: Dict[str, object] - """Configuration for the delivery method. - - The structure of this object is specific to the delivery method. - """ - - delivery_method_id: str - """ID of the delivery method to use for this customer.""" - - -class CustomerRetrieveBillingConfigurationsResponse(BaseModel): - data: List[Data] diff --git a/src/metronome/types/v1/customer_retrieve_response.py b/src/metronome/types/v1/customer_retrieve_response.py deleted file mode 100644 index 9d677be43..000000000 --- a/src/metronome/types/v1/customer_retrieve_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel -from .customer_detail import CustomerDetail - -__all__ = ["CustomerRetrieveResponse"] - - -class CustomerRetrieveResponse(BaseModel): - data: CustomerDetail diff --git a/src/metronome/types/v1/customer_set_billing_configurations_params.py b/src/metronome/types/v1/customer_set_billing_configurations_params.py deleted file mode 100644 index 0b2d2ae2d..000000000 --- a/src/metronome/types/v1/customer_set_billing_configurations_params.py +++ /dev/null @@ -1,63 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Iterable -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["CustomerSetBillingConfigurationsParams", "Data"] - - -class CustomerSetBillingConfigurationsParams(TypedDict, total=False): - data: Required[Iterable[Data]] - - -class Data(TypedDict, total=False): - billing_provider: Required[ - Literal[ - "aws_marketplace", - "stripe", - "netsuite", - "custom", - "azure_marketplace", - "quickbooks_online", - "workday", - "gcp_marketplace", - "metronome", - ] - ] - """The billing provider set for this configuration.""" - - customer_id: Required[str] - - configuration: Dict[str, object] - """Configuration for the billing provider. - - The structure of this object is specific to the billing provider and delivery - method combination. Defaults to an empty object, however, for most billing - provider + delivery method combinations, it will not be a valid configuration. - For AWS marketplace configurations, the aws_is_subscription_product flag can be - used to indicate a product with usage-based pricing. More information can be - found - [here](https://docs.metronome.com/invoice-customers/solutions/marketplaces/invoice-aws/#provision-aws-marketplace-customers-in-metronome). - """ - - delivery_method: Literal["direct_to_billing_provider", "aws_sqs", "tackle", "aws_sns"] - """The method to use for delivering invoices to this customer. - - If not provided, the `delivery_method_id` must be provided. - """ - - delivery_method_id: str - """ID of the delivery method to use for this customer. - - If not provided, the `delivery_method` must be provided. - """ - - tax_provider: Literal["anrok", "avalara", "stripe"] - """ - Specifies which tax provider Metronome should use for tax calculation when - billing through Stripe. This is only supported for Stripe billing provider - configurations with auto_charge_payment_intent or manual_charge_payment_intent - collection methods. - """ diff --git a/src/metronome/types/v1/customer_set_billing_configurations_response.py b/src/metronome/types/v1/customer_set_billing_configurations_response.py deleted file mode 100644 index 590cc08aa..000000000 --- a/src/metronome/types/v1/customer_set_billing_configurations_response.py +++ /dev/null @@ -1,48 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["CustomerSetBillingConfigurationsResponse", "Data"] - - -class Data(BaseModel): - id: Optional[str] = None - """ID of the created configuration""" - - billing_provider: Optional[ - Literal[ - "aws_marketplace", - "stripe", - "netsuite", - "custom", - "azure_marketplace", - "quickbooks_online", - "workday", - "gcp_marketplace", - "metronome", - ] - ] = None - """The billing provider set for this configuration.""" - - configuration: Optional[Dict[str, object]] = None - """Configuration for the billing provider. - - The structure of this object is specific to the billing provider and delivery - method combination. - """ - - customer_id: Optional[str] = None - """ID of the customer this configuration is associated with.""" - - delivery_method_id: Optional[str] = None - """ID of the delivery method used for this customer configuration.""" - - tax_provider: Optional[Literal["anrok", "avalara", "stripe"]] = None - """The tax provider set for this configuration.""" - - -class CustomerSetBillingConfigurationsResponse(BaseModel): - data: List[Data] diff --git a/src/metronome/types/v1/customer_set_ingest_aliases_params.py b/src/metronome/types/v1/customer_set_ingest_aliases_params.py deleted file mode 100644 index cadfb2faa..000000000 --- a/src/metronome/types/v1/customer_set_ingest_aliases_params.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -from ..._types import SequenceNotStr - -__all__ = ["CustomerSetIngestAliasesParams"] - - -class CustomerSetIngestAliasesParams(TypedDict, total=False): - customer_id: Required[str] - - ingest_aliases: Required[SequenceNotStr[str]] diff --git a/src/metronome/types/v1/customer_set_name_params.py b/src/metronome/types/v1/customer_set_name_params.py deleted file mode 100644 index f95821f42..000000000 --- a/src/metronome/types/v1/customer_set_name_params.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["CustomerSetNameParams"] - - -class CustomerSetNameParams(TypedDict, total=False): - customer_id: Required[str] - - name: Required[str] - """The new name for the customer. - - This will be truncated to 160 characters if the provided name is longer. - """ diff --git a/src/metronome/types/v1/customer_set_name_response.py b/src/metronome/types/v1/customer_set_name_response.py deleted file mode 100644 index ad92d73d9..000000000 --- a/src/metronome/types/v1/customer_set_name_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .customer import Customer -from ..._models import BaseModel - -__all__ = ["CustomerSetNameResponse"] - - -class CustomerSetNameResponse(BaseModel): - data: Customer diff --git a/src/metronome/types/v1/customer_update_config_params.py b/src/metronome/types/v1/customer_update_config_params.py deleted file mode 100644 index 9f0ae7063..000000000 --- a/src/metronome/types/v1/customer_update_config_params.py +++ /dev/null @@ -1,21 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import Required, TypedDict - -__all__ = ["CustomerUpdateConfigParams"] - - -class CustomerUpdateConfigParams(TypedDict, total=False): - customer_id: Required[str] - - leave_stripe_invoices_in_draft: Optional[bool] - """Leave in draft or set to auto-advance on invoices sent to Stripe. - - Falls back to the client-level config if unset, which defaults to true if unset. - """ - - salesforce_account_id: Optional[str] - """The Salesforce account ID for the customer""" diff --git a/src/metronome/types/v1/customers/__init__.py b/src/metronome/types/v1/customers/__init__.py deleted file mode 100644 index a806b9195..000000000 --- a/src/metronome/types/v1/customers/__init__.py +++ /dev/null @@ -1,40 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .invoice import Invoice as Invoice -from .customer_alert import CustomerAlert as CustomerAlert -from .plan_add_params import PlanAddParams as PlanAddParams -from .plan_end_params import PlanEndParams as PlanEndParams -from .plan_list_params import PlanListParams as PlanListParams -from .alert_list_params import AlertListParams as AlertListParams -from .plan_add_response import PlanAddResponse as PlanAddResponse -from .plan_end_response import PlanEndResponse as PlanEndResponse -from .alert_reset_params import AlertResetParams as AlertResetParams -from .commit_list_params import CommitListParams as CommitListParams -from .credit_list_params import CreditListParams as CreditListParams -from .plan_list_response import PlanListResponse as PlanListResponse -from .invoice_list_params import InvoiceListParams as InvoiceListParams -from .commit_create_params import CommitCreateParams as CommitCreateParams -from .credit_create_params import CreditCreateParams as CreditCreateParams -from .alert_retrieve_params import AlertRetrieveParams as AlertRetrieveParams -from .commit_create_response import CommitCreateResponse as CommitCreateResponse -from .credit_create_response import CreditCreateResponse as CreditCreateResponse -from .alert_retrieve_response import AlertRetrieveResponse as AlertRetrieveResponse -from .invoice_retrieve_params import InvoiceRetrieveParams as InvoiceRetrieveParams -from .invoice_add_charge_params import InvoiceAddChargeParams as InvoiceAddChargeParams -from .invoice_retrieve_response import InvoiceRetrieveResponse as InvoiceRetrieveResponse -from .invoice_add_charge_response import InvoiceAddChargeResponse as InvoiceAddChargeResponse -from .billing_config_create_params import BillingConfigCreateParams as BillingConfigCreateParams -from .named_schedule_update_params import NamedScheduleUpdateParams as NamedScheduleUpdateParams -from .commit_update_end_date_params import CommitUpdateEndDateParams as CommitUpdateEndDateParams -from .credit_update_end_date_params import CreditUpdateEndDateParams as CreditUpdateEndDateParams -from .invoice_list_breakdowns_params import InvoiceListBreakdownsParams as InvoiceListBreakdownsParams -from .named_schedule_retrieve_params import NamedScheduleRetrieveParams as NamedScheduleRetrieveParams -from .commit_update_end_date_response import CommitUpdateEndDateResponse as CommitUpdateEndDateResponse -from .credit_update_end_date_response import CreditUpdateEndDateResponse as CreditUpdateEndDateResponse -from .billing_config_retrieve_response import BillingConfigRetrieveResponse as BillingConfigRetrieveResponse -from .invoice_list_breakdowns_response import InvoiceListBreakdownsResponse as InvoiceListBreakdownsResponse -from .named_schedule_retrieve_response import NamedScheduleRetrieveResponse as NamedScheduleRetrieveResponse -from .plan_list_price_adjustments_params import PlanListPriceAdjustmentsParams as PlanListPriceAdjustmentsParams -from .plan_list_price_adjustments_response import PlanListPriceAdjustmentsResponse as PlanListPriceAdjustmentsResponse diff --git a/src/metronome/types/v1/customers/alert_list_params.py b/src/metronome/types/v1/customers/alert_list_params.py deleted file mode 100644 index 36ebee108..000000000 --- a/src/metronome/types/v1/customers/alert_list_params.py +++ /dev/null @@ -1,22 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["AlertListParams"] - - -class AlertListParams(TypedDict, total=False): - customer_id: Required[str] - """The Metronome ID of the customer""" - - next_page: str - """Cursor that indicates where the next page of results should start.""" - - alert_statuses: List[Literal["ENABLED", "DISABLED", "ARCHIVED"]] - """Optionally filter by threshold notification status. - - If absent, only enabled notifications will be returned. - """ diff --git a/src/metronome/types/v1/customers/alert_reset_params.py b/src/metronome/types/v1/customers/alert_reset_params.py deleted file mode 100644 index 2b6a03f99..000000000 --- a/src/metronome/types/v1/customers/alert_reset_params.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["AlertResetParams"] - - -class AlertResetParams(TypedDict, total=False): - alert_id: Required[str] - """The Metronome ID of the threshold notification""" - - customer_id: Required[str] - """The Metronome ID of the customer""" diff --git a/src/metronome/types/v1/customers/alert_retrieve_params.py b/src/metronome/types/v1/customers/alert_retrieve_params.py deleted file mode 100644 index 7ff21d38c..000000000 --- a/src/metronome/types/v1/customers/alert_retrieve_params.py +++ /dev/null @@ -1,57 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Iterable -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["AlertRetrieveParams", "GroupValue", "SeatFilter"] - - -class AlertRetrieveParams(TypedDict, total=False): - alert_id: Required[str] - """The Metronome ID of the threshold notification""" - - customer_id: Required[str] - """The Metronome ID of the customer""" - - group_values: Iterable[GroupValue] - """Only present for `spend_threshold_reached` notifications. - - Retrieve the notification for a specific group key-value pair. - """ - - plans_or_contracts: Literal["PLANS", "CONTRACTS"] - """ - When parallel threshold notifications are enabled during migration, this flag - denotes whether to fetch notifications for plans or contracts. - """ - - seat_filter: SeatFilter - """Only allowed for `low_remaining_seat_balance_reached` notifications. - - This filters alerts by the seat group key-value pair. - """ - - -class GroupValue(TypedDict, total=False): - """ - Scopes threshold notification evaluation to a specific presentation group key on individual line items. Only present for spend notifications. - """ - - key: Required[str] - - value: Required[str] - - -class SeatFilter(TypedDict, total=False): - """Only allowed for `low_remaining_seat_balance_reached` notifications. - - This filters alerts by the seat group key-value pair. - """ - - seat_group_key: Required[str] - """The seat group key (e.g., "seat_id", "user_id")""" - - seat_group_value: Required[str] - """The specific seat identifier to filter by""" diff --git a/src/metronome/types/v1/customers/alert_retrieve_response.py b/src/metronome/types/v1/customers/alert_retrieve_response.py deleted file mode 100644 index 4977aa606..000000000 --- a/src/metronome/types/v1/customers/alert_retrieve_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel -from .customer_alert import CustomerAlert - -__all__ = ["AlertRetrieveResponse"] - - -class AlertRetrieveResponse(BaseModel): - data: CustomerAlert diff --git a/src/metronome/types/v1/customers/billing_config_create_params.py b/src/metronome/types/v1/customers/billing_config_create_params.py deleted file mode 100644 index 3eef60621..000000000 --- a/src/metronome/types/v1/customers/billing_config_create_params.py +++ /dev/null @@ -1,73 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["BillingConfigCreateParams"] - - -class BillingConfigCreateParams(TypedDict, total=False): - customer_id: Required[str] - - billing_provider_type: Required[ - Literal[ - "aws_marketplace", - "stripe", - "netsuite", - "custom", - "azure_marketplace", - "quickbooks_online", - "workday", - "gcp_marketplace", - "metronome", - ] - ] - - billing_provider_customer_id: Required[str] - """The customer ID in the billing provider's system. - - For Azure, this is the subscription ID. - """ - - aws_customer_account_id: str - - aws_customer_id: str - - aws_product_code: str - - aws_region: Literal[ - "af-south-1", - "ap-east-1", - "ap-northeast-1", - "ap-northeast-2", - "ap-northeast-3", - "ap-south-1", - "ap-southeast-1", - "ap-southeast-2", - "ca-central-1", - "cn-north-1", - "cn-northwest-1", - "eu-central-1", - "eu-north-1", - "eu-south-1", - "eu-west-1", - "eu-west-2", - "eu-west-3", - "me-south-1", - "sa-east-1", - "us-east-1", - "us-east-2", - "us-gov-east-1", - "us-gov-west-1", - "us-west-1", - "us-west-2", - ] - - stripe_collection_method: Literal[ - "charge_automatically", "send_invoice", "auto_charge_payment_intent", "manually_charge_payment_intent" - ] - """ - The collection method for the customer's invoices. NOTE: - `auto_charge_payment_intent` and `manually_charge_payment_intent` are in beta. - """ diff --git a/src/metronome/types/v1/customers/billing_config_retrieve_response.py b/src/metronome/types/v1/customers/billing_config_retrieve_response.py deleted file mode 100644 index e5d4e1e3c..000000000 --- a/src/metronome/types/v1/customers/billing_config_retrieve_response.py +++ /dev/null @@ -1,91 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["BillingConfigRetrieveResponse", "Data"] - - -class Data(BaseModel): - aws_customer_account_id: Optional[str] = None - - aws_customer_id: Optional[str] = None - - aws_expiration_date: Optional[datetime] = None - """Contract expiration date for the customer. - - The expected format is RFC 3339 and can be retrieved from - [AWS's GetEntitlements API](https://docs.aws.amazon.com/marketplaceentitlement/latest/APIReference/API_GetEntitlements.html). - """ - - aws_is_subscription_product: Optional[bool] = None - """True if the aws_product_code is a SAAS subscription product, false otherwise.""" - - aws_product_code: Optional[str] = None - - aws_region: Optional[ - Literal[ - "af-south-1", - "ap-east-1", - "ap-northeast-1", - "ap-northeast-2", - "ap-northeast-3", - "ap-south-1", - "ap-southeast-1", - "ap-southeast-2", - "ca-central-1", - "cn-north-1", - "cn-northwest-1", - "eu-central-1", - "eu-north-1", - "eu-south-1", - "eu-west-1", - "eu-west-2", - "eu-west-3", - "me-south-1", - "sa-east-1", - "us-east-1", - "us-east-2", - "us-gov-east-1", - "us-gov-west-1", - "us-west-1", - "us-west-2", - ] - ] = None - - azure_expiration_date: Optional[datetime] = None - """Subscription term start/end date for the customer. - - The expected format is RFC 3339 and can be retrieved from - [Azure's Get Subscription API](https://learn.microsoft.com/en-us/partner-center/marketplace/partner-center-portal/pc-saas-fulfillment-subscription-api#get-subscription). - """ - - azure_plan_id: Optional[str] = None - - azure_start_date: Optional[datetime] = None - """Subscription term start/end date for the customer. - - The expected format is RFC 3339 and can be retrieved from - [Azure's Get Subscription API](https://learn.microsoft.com/en-us/partner-center/marketplace/partner-center-portal/pc-saas-fulfillment-subscription-api#get-subscription). - """ - - azure_subscription_status: Optional[ - Literal["Subscribed", "Unsubscribed", "Suspended", "PendingFulfillmentStart"] - ] = None - - billing_provider_customer_id: Optional[str] = None - - stripe_collection_method: Optional[ - Literal["charge_automatically", "send_invoice", "auto_charge_payment_intent", "manually_charge_payment_intent"] - ] = None - """ - The collection method for the customer's invoices. NOTE: - `auto_charge_payment_intent` and `manually_charge_payment_intent` are in beta. - """ - - -class BillingConfigRetrieveResponse(BaseModel): - data: Data diff --git a/src/metronome/types/v1/customers/commit_create_params.py b/src/metronome/types/v1/customers/commit_create_params.py deleted file mode 100644 index b808b058e..000000000 --- a/src/metronome/types/v1/customers/commit_create_params.py +++ /dev/null @@ -1,226 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ...._types import SequenceNotStr -from ...._utils import PropertyInfo -from ...shared_params.commit_specifier_input import CommitSpecifierInput - -__all__ = [ - "CommitCreateParams", - "AccessSchedule", - "AccessScheduleScheduleItem", - "InvoiceSchedule", - "InvoiceScheduleRecurringSchedule", - "InvoiceScheduleScheduleItem", -] - - -class CommitCreateParams(TypedDict, total=False): - access_schedule: Required[AccessSchedule] - """Schedule for distributing the commit to the customer. - - For "POSTPAID" commits only one schedule item is allowed and amount must match - invoice_schedule total. - """ - - customer_id: Required[str] - - priority: Required[float] - """ - If multiple credits or commits are applicable, the one with the lower priority - will apply first. - """ - - product_id: Required[str] - """ID of the fixed product associated with the commit. - - This is required because products are used to invoice the commit amount. - """ - - type: Required[Literal["PREPAID", "POSTPAID"]] - - applicable_contract_ids: SequenceNotStr[str] - """Which contract the commit applies to. - - If not provided, the commit applies to all contracts. - """ - - applicable_product_ids: SequenceNotStr[str] - """Which products the commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - applicable_product_tags: SequenceNotStr[str] - """Which tags the commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: str - """Used only in UI/API. It is not exposed to end customers.""" - - invoice_contract_id: str - """The contract that this commit will be billed on. - - This is required for "POSTPAID" commits and for "PREPAID" commits unless there - is no invoice schedule above (i.e., the commit is 'free'), or if do_not_invoice - is set to true. - """ - - invoice_schedule: InvoiceSchedule - """ - Required for "POSTPAID" commits: the true up invoice will be generated at this - time and only one schedule item is allowed; the total must match - accesss_schedule amount. Optional for "PREPAID" commits: if not provided, this - will be a "complimentary" commit with no invoice. - """ - - name: str - """displayed on invoices""" - - netsuite_sales_order_id: str - """This field's availability is dependent on your client's configuration.""" - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - - salesforce_opportunity_id: str - """This field's availability is dependent on your client's configuration.""" - - specifiers: Iterable[CommitSpecifierInput] - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - """ - - uniqueness_key: str - """Prevents the creation of duplicates. - - If a request to create a commit or credit is made with a uniqueness key that was - previously used to create a commit or credit, a new record will not be created - and the request will fail with a 409 error. - """ - - -class AccessScheduleScheduleItem(TypedDict, total=False): - amount: Required[float] - - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (exclusive)""" - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (inclusive)""" - - -class AccessSchedule(TypedDict, total=False): - """Schedule for distributing the commit to the customer. - - For "POSTPAID" commits only one schedule item is allowed and amount must match invoice_schedule total. - """ - - schedule_items: Required[Iterable[AccessScheduleScheduleItem]] - - credit_type_id: str - """Defaults to USD (cents) if not passed""" - - -class InvoiceScheduleRecurringSchedule(TypedDict, total=False): - """Enter the unit price and quantity for the charge or instead only send the amount. - - If amount is sent, the unit price is assumed to be the amount and quantity is inferred to be 1. - """ - - amount_distribution: Required[Literal["DIVIDED", "DIVIDED_ROUNDED", "EACH"]] - - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (exclusive).""" - - frequency: Required[Literal["MONTHLY", "QUARTERLY", "SEMI_ANNUAL", "ANNUAL"]] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (inclusive).""" - - amount: float - """Amount for the charge. - - Can be provided instead of unit_price and quantity. If amount is sent, the - unit_price is assumed to be the amount and quantity is inferred to be 1. - """ - - quantity: float - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount and must be specified - with unit_price. If specified amount cannot be provided. - """ - - unit_price: float - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified - with quantity. If specified amount cannot be provided. - """ - - -class InvoiceScheduleScheduleItem(TypedDict, total=False): - timestamp: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """timestamp of the scheduled event""" - - amount: float - """Amount for the charge. - - Can be provided instead of unit_price and quantity. If amount is sent, the - unit_price is assumed to be the amount and quantity is inferred to be 1. - """ - - quantity: float - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount and must be specified - with unit_price. If specified amount cannot be provided. - """ - - unit_price: float - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified - with quantity. If specified amount cannot be provided. - """ - - -class InvoiceSchedule(TypedDict, total=False): - """ - Required for "POSTPAID" commits: the true up invoice will be generated at this time and only one schedule item is allowed; the total must match accesss_schedule amount. Optional for "PREPAID" commits: if not provided, this will be a "complimentary" commit with no invoice. - """ - - credit_type_id: str - """Defaults to USD (cents) if not passed.""" - - do_not_invoice: bool - """This field is only applicable to commit invoice schedules. - - If true, this schedule will not generate an invoice. - """ - - recurring_schedule: InvoiceScheduleRecurringSchedule - """Enter the unit price and quantity for the charge or instead only send the - amount. - - If amount is sent, the unit price is assumed to be the amount and quantity is - inferred to be 1. - """ - - schedule_items: Iterable[InvoiceScheduleScheduleItem] - """Either provide amount or provide both unit_price and quantity.""" diff --git a/src/metronome/types/v1/customers/commit_create_response.py b/src/metronome/types/v1/customers/commit_create_response.py deleted file mode 100644 index 336112fa2..000000000 --- a/src/metronome/types/v1/customers/commit_create_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel -from ...shared.id import ID - -__all__ = ["CommitCreateResponse"] - - -class CommitCreateResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/customers/commit_list_params.py b/src/metronome/types/v1/customers/commit_list_params.py deleted file mode 100644 index 26292aeaa..000000000 --- a/src/metronome/types/v1/customers/commit_list_params.py +++ /dev/null @@ -1,50 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ...._utils import PropertyInfo - -__all__ = ["CommitListParams"] - - -class CommitListParams(TypedDict, total=False): - customer_id: Required[str] - - commit_id: str - - covering_date: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Include only commits that have access schedules that "cover" the provided date""" - - effective_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Include only commits that have any access before the provided date (exclusive)""" - - include_archived: bool - """Include archived commits and commits from archived contracts.""" - - include_balance: bool - """Include the balance in the response. - - Setting this flag may cause the query to be slower. - """ - - include_contract_commits: bool - """Include commits on the contract level.""" - - include_ledgers: bool - """Include commit ledgers in the response. - - Setting this flag may cause the query to be slower. - """ - - limit: int - """The maximum number of commits to return. Defaults to 25.""" - - next_page: str - """The next page token from a previous response.""" - - starting_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Include only commits that have any access on or after the provided date""" diff --git a/src/metronome/types/v1/customers/commit_update_end_date_params.py b/src/metronome/types/v1/customers/commit_update_end_date_params.py deleted file mode 100644 index 60e5c32dc..000000000 --- a/src/metronome/types/v1/customers/commit_update_end_date_params.py +++ /dev/null @@ -1,32 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ...._utils import PropertyInfo - -__all__ = ["CommitUpdateEndDateParams"] - - -class CommitUpdateEndDateParams(TypedDict, total=False): - commit_id: Required[str] - """ID of the commit to update. Only supports "PREPAID" commits.""" - - customer_id: Required[str] - """ID of the customer whose commit is to be updated""" - - access_ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """ - RFC 3339 timestamp indicating when access to the commit will end and it will no - longer be possible to draw it down (exclusive). If not provided, the access will - not be updated. - """ - - invoices_ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """ - RFC 3339 timestamp indicating when the commit will stop being invoiced - (exclusive). If not provided, the invoice schedule will not be updated. - """ diff --git a/src/metronome/types/v1/customers/commit_update_end_date_response.py b/src/metronome/types/v1/customers/commit_update_end_date_response.py deleted file mode 100644 index 8438babc4..000000000 --- a/src/metronome/types/v1/customers/commit_update_end_date_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel -from ...shared.id import ID - -__all__ = ["CommitUpdateEndDateResponse"] - - -class CommitUpdateEndDateResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/customers/credit_create_params.py b/src/metronome/types/v1/customers/credit_create_params.py deleted file mode 100644 index 3d8cd4d83..000000000 --- a/src/metronome/types/v1/customers/credit_create_params.py +++ /dev/null @@ -1,100 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ...._types import SequenceNotStr -from ...._utils import PropertyInfo -from ...shared_params.commit_specifier_input import CommitSpecifierInput - -__all__ = ["CreditCreateParams", "AccessSchedule", "AccessScheduleScheduleItem"] - - -class CreditCreateParams(TypedDict, total=False): - access_schedule: Required[AccessSchedule] - """Schedule for distributing the credit to the customer.""" - - customer_id: Required[str] - - priority: Required[float] - """ - If multiple credits or commits are applicable, the one with the lower priority - will apply first. - """ - - product_id: Required[str] - - applicable_contract_ids: SequenceNotStr[str] - """Which contract the credit applies to. - - If not provided, the credit applies to all contracts. - """ - - applicable_product_ids: SequenceNotStr[str] - """Which products the credit applies to. - - If both applicable_product_ids and applicable_product_tags are not provided, the - credit applies to all products. - """ - - applicable_product_tags: SequenceNotStr[str] - """Which tags the credit applies to. - - If both applicable_product_ids and applicable_product_tags are not provided, the - credit applies to all products. - """ - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: str - """Used only in UI/API. It is not exposed to end customers.""" - - name: str - """displayed on invoices""" - - netsuite_sales_order_id: str - """This field's availability is dependent on your client's configuration.""" - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - - salesforce_opportunity_id: str - """This field's availability is dependent on your client's configuration.""" - - specifiers: Iterable[CommitSpecifierInput] - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - """ - - uniqueness_key: str - """Prevents the creation of duplicates. - - If a request to create a commit or credit is made with a uniqueness key that was - previously used to create a commit or credit, a new record will not be created - and the request will fail with a 409 error. - """ - - -class AccessScheduleScheduleItem(TypedDict, total=False): - amount: Required[float] - - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (exclusive)""" - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (inclusive)""" - - -class AccessSchedule(TypedDict, total=False): - """Schedule for distributing the credit to the customer.""" - - schedule_items: Required[Iterable[AccessScheduleScheduleItem]] - - credit_type_id: str - """Defaults to USD (cents) if not passed""" diff --git a/src/metronome/types/v1/customers/credit_create_response.py b/src/metronome/types/v1/customers/credit_create_response.py deleted file mode 100644 index 493c12430..000000000 --- a/src/metronome/types/v1/customers/credit_create_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel -from ...shared.id import ID - -__all__ = ["CreditCreateResponse"] - - -class CreditCreateResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/customers/credit_list_params.py b/src/metronome/types/v1/customers/credit_list_params.py deleted file mode 100644 index 85dd064d0..000000000 --- a/src/metronome/types/v1/customers/credit_list_params.py +++ /dev/null @@ -1,50 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ...._utils import PropertyInfo - -__all__ = ["CreditListParams"] - - -class CreditListParams(TypedDict, total=False): - customer_id: Required[str] - - covering_date: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Return only credits that have access schedules that "cover" the provided date""" - - credit_id: str - - effective_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Include only credits that have any access before the provided date (exclusive)""" - - include_archived: bool - """Include archived credits and credits from archived contracts.""" - - include_balance: bool - """Include the balance in the response. - - Setting this flag may cause the query to be slower. - """ - - include_contract_credits: bool - """Include credits on the contract level.""" - - include_ledgers: bool - """Include credit ledgers in the response. - - Setting this flag may cause the query to be slower. - """ - - limit: int - """The maximum number of commits to return. Defaults to 25.""" - - next_page: str - """The next page token from a previous response.""" - - starting_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Include only credits that have any access on or after the provided date""" diff --git a/src/metronome/types/v1/customers/credit_update_end_date_params.py b/src/metronome/types/v1/customers/credit_update_end_date_params.py deleted file mode 100644 index 7b00f8610..000000000 --- a/src/metronome/types/v1/customers/credit_update_end_date_params.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ...._utils import PropertyInfo - -__all__ = ["CreditUpdateEndDateParams"] - - -class CreditUpdateEndDateParams(TypedDict, total=False): - access_ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """ - RFC 3339 timestamp indicating when access to the credit will end and it will no - longer be possible to draw it down (exclusive). - """ - - credit_id: Required[str] - """ID of the commit to update""" - - customer_id: Required[str] - """ID of the customer whose credit is to be updated""" diff --git a/src/metronome/types/v1/customers/credit_update_end_date_response.py b/src/metronome/types/v1/customers/credit_update_end_date_response.py deleted file mode 100644 index 7f2293ff1..000000000 --- a/src/metronome/types/v1/customers/credit_update_end_date_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel -from ...shared.id import ID - -__all__ = ["CreditUpdateEndDateResponse"] - - -class CreditUpdateEndDateResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/customers/customer_alert.py b/src/metronome/types/v1/customers/customer_alert.py deleted file mode 100644 index ec72edf0d..000000000 --- a/src/metronome/types/v1/customers/customer_alert.py +++ /dev/null @@ -1,150 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime -from typing_extensions import Literal - -from ...._models import BaseModel -from ...shared.credit_type_data import CreditTypeData - -__all__ = [ - "CustomerAlert", - "Alert", - "AlertCustomFieldFilter", - "AlertGroupKeyFilter", - "AlertGroupValue", - "AlertSeatFilter", -] - - -class AlertCustomFieldFilter(BaseModel): - entity: Literal["Contract", "Commit", "ContractCredit"] - - key: str - - value: str - - -class AlertGroupKeyFilter(BaseModel): - """ - Scopes threshold notification evaluation to a specific presentation group key on individual line items. Only present for spend notifications. - """ - - key: str - - value: str - - -class AlertGroupValue(BaseModel): - key: str - - value: Optional[str] = None - - -class AlertSeatFilter(BaseModel): - """Only present for low_remaining_seat_balance_reached notifications. - - The seat group key or seat group key-value pair the alert is scoped to. - """ - - seat_group_key: str - """The seat group key (e.g., "seat_id", "user_id") that the alert is scoped to.""" - - seat_group_value: Optional[str] = None - """The seat group value that the alert is scoped to.""" - - -class Alert(BaseModel): - id: str - """the Metronome ID of the threshold notification""" - - name: str - """Name of the threshold notification""" - - status: Literal["enabled", "archived", "disabled"] - """Status of the threshold notification""" - - threshold: float - """Threshold value of the notification policy""" - - type: Literal[ - "low_credit_balance_reached", - "spend_threshold_reached", - "monthly_invoice_total_spend_threshold_reached", - "low_remaining_days_in_plan_reached", - "low_remaining_credit_percentage_reached", - "usage_threshold_reached", - "low_remaining_days_for_commit_segment_reached", - "low_remaining_commit_balance_reached", - "low_remaining_commit_percentage_reached", - "low_remaining_days_for_contract_credit_segment_reached", - "low_remaining_contract_credit_balance_reached", - "low_remaining_contract_credit_percentage_reached", - "low_remaining_contract_credit_and_commit_balance_reached", - "low_remaining_seat_balance_reached", - "invoice_total_reached", - ] - """Type of the threshold notification""" - - updated_at: datetime - """Timestamp for when the threshold notification was last updated""" - - credit_grant_type_filters: Optional[List[str]] = None - """ - An array of strings, representing a way to filter the credit grant this - threshold notification applies to, by looking at the credit_grant_type field on - the credit grant. This field is only defined for CreditPercentage and - CreditBalance notifications - """ - - credit_type: Optional[CreditTypeData] = None - - custom_field_filters: Optional[List[AlertCustomFieldFilter]] = None - """ - A list of custom field filters for notification types that support advanced - filtering - """ - - group_key_filter: Optional[AlertGroupKeyFilter] = None - """ - Scopes threshold notification evaluation to a specific presentation group key on - individual line items. Only present for spend notifications. - """ - - group_values: Optional[List[AlertGroupValue]] = None - """Only present for `spend_threshold_reached` notifications. - - Scope notification to a specific group key on individual line items. - """ - - invoice_types_filter: Optional[List[str]] = None - """Only supported for invoice_total_reached threshold notifications. - - A list of invoice types to evaluate. - """ - - seat_filter: Optional[AlertSeatFilter] = None - """Only present for low_remaining_seat_balance_reached notifications. - - The seat group key or seat group key-value pair the alert is scoped to. - """ - - uniqueness_key: Optional[str] = None - """Prevents the creation of duplicates. - - If a request to create a record is made with a previously used uniqueness key, a - new record will not be created and the request will fail with a 409 error. - """ - - -class CustomerAlert(BaseModel): - alert: Alert - - customer_status: Optional[Literal["ok", "in_alarm", "evaluating"]] = None - """The status of the threshold notification. - - If the notification is archived, null will be returned. - """ - - triggered_by: Optional[str] = None - """If present, indicates the reason the threshold notification was triggered.""" diff --git a/src/metronome/types/v1/customers/invoice.py b/src/metronome/types/v1/customers/invoice.py deleted file mode 100644 index 6d55c7bae..000000000 --- a/src/metronome/types/v1/customers/invoice.py +++ /dev/null @@ -1,604 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from datetime import datetime -from typing_extensions import Literal - -from ...._models import BaseModel -from ...shared.rate import Rate -from ...shared.credit_type_data import CreditTypeData - -__all__ = [ - "Invoice", - "LineItem", - "LineItemAppliedCommitOrCredit", - "LineItemOrigin", - "LineItemPostpaidCommit", - "LineItemSubLineItem", - "LineItemSubLineItemTierPeriod", - "LineItemSubLineItemTier", - "LineItemTier", - "ConstituentInvoice", - "CorrectionRecord", - "CorrectionRecordCorrectedExternalInvoice", - "CorrectionRecordCorrectedExternalInvoiceTax", - "ExternalInvoice", - "ExternalInvoiceTax", - "InvoiceAdjustment", - "Payer", - "ResellerRoyalty", - "ResellerRoyaltyAwsOptions", - "ResellerRoyaltyGcpOptions", - "RevenueSystemInvoice", -] - - -class LineItemAppliedCommitOrCredit(BaseModel): - """Details about the credit or commit that was applied to this line item. - - Only present on line items with product of `USAGE`, `SUBSCRIPTION` or `COMPOSITE` types. - """ - - id: str - - type: Literal["PREPAID", "POSTPAID", "CREDIT"] - - -class LineItemOrigin(BaseModel): - """Present on line items from invoices with type USAGE_CONSOLIDATED. - - Indicates the original customer, contract, invoice and line item from which this line item was copied. - """ - - contract_id: str - - customer_id: str - - invoice_id: str - - line_item_id: str - - -class LineItemPostpaidCommit(BaseModel): - """Only present for line items paying for a postpaid commit true-up.""" - - id: str - - -class LineItemSubLineItemTierPeriod(BaseModel): - """when the current tier started and ends (for tiered charges only)""" - - starting_at: datetime - - ending_before: Optional[datetime] = None - - -class LineItemSubLineItemTier(BaseModel): - price: float - - quantity: float - - starting_at: float - """at what metric amount this tier begins""" - - subtotal: float - - -class LineItemSubLineItem(BaseModel): - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - name: str - - quantity: float - - subtotal: float - - charge_id: Optional[str] = None - - credit_grant_id: Optional[str] = None - - end_date: Optional[datetime] = None - """The end date for the charge (for seats charges only).""" - - price: Optional[float] = None - """ - the unit price for this charge, present only if the charge is not tiered and the - quantity is nonzero - """ - - start_date: Optional[datetime] = None - """The start date for the charge (for seats charges only).""" - - tier_period: Optional[LineItemSubLineItemTierPeriod] = None - """when the current tier started and ends (for tiered charges only)""" - - tiers: Optional[List[LineItemSubLineItemTier]] = None - - -class LineItemTier(BaseModel): - """Populated if the line item has a tiered price.""" - - level: float - - starting_at: str - - size: Optional[str] = None - - -class LineItem(BaseModel): - credit_type: CreditTypeData - - name: str - - total: float - - type: str - """The type of line item. - - - `scheduled`: Line item is associated with a scheduled charge. View the - scheduled_charge_id on the line item. - - `commit_purchase`: Line item is associated with a payment for a prepaid - commit. View the commit_id on the line item. - - `usage`: Line item is associated with a usage product or composite product. - View the product_id on the line item to determine which product. - - `subscription`: Line item is associated with a subscription. e.g. monthly - recurring payment for an in-advance subscription. - - `applied_commit_or_credit`: On metronome invoices, applied commits and credits - are associated with their own line items. These line items have negative - totals. Use the applied_commit_or_credit object on the line item to understand - the id of the applied commit or credit, and its type. Note that the - application of a postpaid commit is associated with a line item, but the total - on the line item is not included in the invoice's total as postpaid commits - are paid in-arrears. - - `cpu_conversion`: Line item converting between a custom pricing unit and fiat - currency, using the conversion rate set on the rate card. This line item will - appear when there are products priced in custom pricing units, and there is - insufficient prepaid commit/credit in that custom pricing unit to fully cover - the spend. Then, the outstanding spend in custom pricing units will be - converted to fiat currency using a cpu_conversion line item. - """ - - applied_commit_or_credit: Optional[LineItemAppliedCommitOrCredit] = None - """Details about the credit or commit that was applied to this line item. - - Only present on line items with product of `USAGE`, `SUBSCRIPTION` or - `COMPOSITE` types. - """ - - commit_custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - commit_id: Optional[str] = None - """ - For line items with product of `USAGE`, `SUBSCRIPTION`, or `COMPOSITE` types, - the ID of the credit or commit that was applied to this line item. For line - items with product type of `FIXED`, the ID of the prepaid or postpaid commit - that is being paid for. - """ - - commit_netsuite_item_id: Optional[str] = None - - commit_netsuite_sales_order_id: Optional[str] = None - - commit_segment_id: Optional[str] = None - - commit_type: Optional[str] = None - """ - `PrepaidCommit` (for commit types `PREPAID` and `CREDIT`) or `PostpaidCommit` - (for commit type `POSTPAID`). - """ - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - discount_custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - discount_id: Optional[str] = None - """ID of the discount applied to this line item.""" - - ending_before: Optional[datetime] = None - """The line item's end date (exclusive).""" - - group_key: Optional[str] = None - - group_value: Optional[str] = None - - is_prorated: Optional[bool] = None - """Indicates whether the line item is prorated for `SUBSCRIPTION` type product.""" - - list_price: Optional[Rate] = None - """ - Only present for contract invoices and when the `include_list_prices` query - parameter is set to true. This will include the list rate for the charge if - applicable. Only present for usage and subscription line items. - """ - - metadata: Optional[str] = None - - netsuite_invoice_billing_end: Optional[datetime] = None - """The end date for the billing period on the invoice.""" - - netsuite_invoice_billing_start: Optional[datetime] = None - """The start date for the billing period on the invoice.""" - - netsuite_item_id: Optional[str] = None - - origin: Optional[LineItemOrigin] = None - """Present on line items from invoices with type USAGE_CONSOLIDATED. - - Indicates the original customer, contract, invoice and line item from which this - line item was copied. - """ - - postpaid_commit: Optional[LineItemPostpaidCommit] = None - """Only present for line items paying for a postpaid commit true-up.""" - - presentation_group_values: Optional[Dict[str, Optional[str]]] = None - """ - Includes the presentation group values associated with this line item if - presentation group keys are used. - """ - - pricing_group_values: Optional[Dict[str, str]] = None - """ - Includes the pricing group values associated with this line item if dimensional - pricing is used. - """ - - product_custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - product_id: Optional[str] = None - """ID of the product associated with the line item.""" - - product_tags: Optional[List[str]] = None - """The current product tags associated with the line item's `product_id`.""" - - product_type: Optional[str] = None - """The type of the line item's product. - - Possible values are `FixedProductListItem` (for `FIXED` type products), - `UsageProductListItem` (for `USAGE` type products), - `SubscriptionProductListItem` (for `SUBSCRIPTION` type products) or - `CompositeProductListItem` (for `COMPOSITE` type products). For scheduled - charges, commit and credit payments, the value is `FixedProductListItem`. - """ - - professional_service_custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - professional_service_id: Optional[str] = None - - quantity: Optional[float] = None - """The quantity associated with the line item.""" - - reseller_type: Optional[Literal["AWS", "AWS_PRO_SERVICE", "GCP", "GCP_PRO_SERVICE"]] = None - - scheduled_charge_custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - scheduled_charge_id: Optional[str] = None - """ID of scheduled charge.""" - - starting_at: Optional[datetime] = None - """The line item's start date (inclusive).""" - - sub_line_items: Optional[List[LineItemSubLineItem]] = None - - subscription_custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - subscription_id: Optional[str] = None - """ID of the subscription that this line item is associated with. - - Only present on line items with product of `SUBSCRIPTION` type. - """ - - tier: Optional[LineItemTier] = None - """Populated if the line item has a tiered price.""" - - unit_price: Optional[float] = None - """The unit price associated with the line item.""" - - -class ConstituentInvoice(BaseModel): - contract_id: str - - customer_id: str - - invoice_id: str - - -class CorrectionRecordCorrectedExternalInvoiceTax(BaseModel): - """Tax details for the invoice, if available from the billing provider.""" - - total_tax_amount: Optional[float] = None - """The total tax amount applied to the invoice.""" - - total_taxable_amount: Optional[float] = None - """The total taxable amount of the invoice.""" - - transaction_id: Optional[str] = None - """The transaction ID associated with the tax calculation.""" - - -class CorrectionRecordCorrectedExternalInvoice(BaseModel): - billing_provider_type: Literal[ - "aws_marketplace", - "stripe", - "netsuite", - "custom", - "azure_marketplace", - "quickbooks_online", - "workday", - "gcp_marketplace", - "metronome", - ] - - billing_provider_error: Optional[str] = None - """Error message from the billing provider, if available.""" - - external_payment_id: Optional[str] = None - """The ID of the payment in the external system, if available.""" - - external_status: Optional[ - Literal[ - "DRAFT", - "FINALIZED", - "PAID", - "PARTIALLY_PAID", - "UNCOLLECTIBLE", - "VOID", - "DELETED", - "PAYMENT_FAILED", - "INVALID_REQUEST_ERROR", - "SKIPPED", - "SENT", - "QUEUED", - ] - ] = None - - invoice_id: Optional[str] = None - - invoiced_sub_total: Optional[float] = None - """The subtotal amount invoiced, if available from the billing provider.""" - - invoiced_total: Optional[float] = None - """The total amount invoiced, if available from the billing provider.""" - - issued_at_timestamp: Optional[datetime] = None - - pdf_url: Optional[str] = None - """A URL to the PDF of the invoice, if available from the billing provider.""" - - tax: Optional[CorrectionRecordCorrectedExternalInvoiceTax] = None - """Tax details for the invoice, if available from the billing provider.""" - - -class CorrectionRecord(BaseModel): - corrected_invoice_id: str - - memo: str - - reason: str - - corrected_external_invoice: Optional[CorrectionRecordCorrectedExternalInvoice] = None - - -class ExternalInvoiceTax(BaseModel): - """Tax details for the invoice, if available from the billing provider.""" - - total_tax_amount: Optional[float] = None - """The total tax amount applied to the invoice.""" - - total_taxable_amount: Optional[float] = None - """The total taxable amount of the invoice.""" - - transaction_id: Optional[str] = None - """The transaction ID associated with the tax calculation.""" - - -class ExternalInvoice(BaseModel): - billing_provider_type: Literal[ - "aws_marketplace", - "stripe", - "netsuite", - "custom", - "azure_marketplace", - "quickbooks_online", - "workday", - "gcp_marketplace", - "metronome", - ] - - billing_provider_error: Optional[str] = None - """Error message from the billing provider, if available.""" - - external_payment_id: Optional[str] = None - """The ID of the payment in the external system, if available.""" - - external_status: Optional[ - Literal[ - "DRAFT", - "FINALIZED", - "PAID", - "PARTIALLY_PAID", - "UNCOLLECTIBLE", - "VOID", - "DELETED", - "PAYMENT_FAILED", - "INVALID_REQUEST_ERROR", - "SKIPPED", - "SENT", - "QUEUED", - ] - ] = None - - invoice_id: Optional[str] = None - - invoiced_sub_total: Optional[float] = None - """The subtotal amount invoiced, if available from the billing provider.""" - - invoiced_total: Optional[float] = None - """The total amount invoiced, if available from the billing provider.""" - - issued_at_timestamp: Optional[datetime] = None - - pdf_url: Optional[str] = None - """A URL to the PDF of the invoice, if available from the billing provider.""" - - tax: Optional[ExternalInvoiceTax] = None - """Tax details for the invoice, if available from the billing provider.""" - - -class InvoiceAdjustment(BaseModel): - credit_type: CreditTypeData - - name: str - - total: float - - credit_grant_custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - credit_grant_id: Optional[str] = None - - -class Payer(BaseModel): - """Required for account hierarchy usage invoices. - - An object containing the contract and customer UUIDs that pay for this invoice. - """ - - contract_id: str - - customer_id: str - - -class ResellerRoyaltyAwsOptions(BaseModel): - aws_account_number: Optional[str] = None - - aws_offer_id: Optional[str] = None - - aws_payer_reference_id: Optional[str] = None - - -class ResellerRoyaltyGcpOptions(BaseModel): - gcp_account_id: Optional[str] = None - - gcp_offer_id: Optional[str] = None - - -class ResellerRoyalty(BaseModel): - """Only present for contract invoices with reseller royalties.""" - - fraction: str - - netsuite_reseller_id: str - - reseller_type: Literal["AWS", "AWS_PRO_SERVICE", "GCP", "GCP_PRO_SERVICE"] - - aws_options: Optional[ResellerRoyaltyAwsOptions] = None - - gcp_options: Optional[ResellerRoyaltyGcpOptions] = None - - -class RevenueSystemInvoice(BaseModel): - revenue_system_external_entity_type: str - - revenue_system_provider: str - - sync_status: str - - error_message: Optional[str] = None - """The error message from the revenue system, if available.""" - - revenue_system_external_entity_id: Optional[str] = None - - -class Invoice(BaseModel): - id: str - - credit_type: CreditTypeData - - customer_id: str - - line_items: List[LineItem] - - status: str - - total: float - - type: str - - amendment_id: Optional[str] = None - - billable_status: Optional[object] = None - """This field's availability is dependent on your client's configuration.""" - - constituent_invoices: Optional[List[ConstituentInvoice]] = None - """Required on invoices with type USAGE_CONSOLIDATED. - - List of constituent invoices that were consolidated to create this invoice. - """ - - contract_custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - contract_id: Optional[str] = None - - correction_record: Optional[CorrectionRecord] = None - - created_at: Optional[datetime] = None - """When the invoice was created (UTC). - - This field is present for correction invoices only. - """ - - custom_fields: Optional[Dict[str, object]] = None - - customer_custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - end_timestamp: Optional[datetime] = None - """End of the usage period this invoice covers (UTC)""" - - external_invoice: Optional[ExternalInvoice] = None - - invoice_adjustments: Optional[List[InvoiceAdjustment]] = None - - issued_at: Optional[datetime] = None - """When the invoice was issued (UTC)""" - - net_payment_terms_days: Optional[float] = None - - netsuite_sales_order_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - payer: Optional[Payer] = None - """Required for account hierarchy usage invoices. - - An object containing the contract and customer UUIDs that pay for this invoice. - """ - - plan_custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - plan_id: Optional[str] = None - - plan_name: Optional[str] = None - - reseller_royalty: Optional[ResellerRoyalty] = None - """Only present for contract invoices with reseller royalties.""" - - revenue_system_invoices: Optional[List[RevenueSystemInvoice]] = None - - salesforce_opportunity_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - start_timestamp: Optional[datetime] = None - """Beginning of the usage period this invoice covers (UTC)""" - - subtotal: Optional[float] = None diff --git a/src/metronome/types/v1/customers/invoice_add_charge_params.py b/src/metronome/types/v1/customers/invoice_add_charge_params.py deleted file mode 100644 index a22c9fcf6..000000000 --- a/src/metronome/types/v1/customers/invoice_add_charge_params.py +++ /dev/null @@ -1,38 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ...._utils import PropertyInfo - -__all__ = ["InvoiceAddChargeParams"] - - -class InvoiceAddChargeParams(TypedDict, total=False): - customer_id: Required[str] - - charge_id: Required[str] - """The Metronome ID of the charge to add to the invoice. - - Note that the charge must be on a product that is not on the current plan, and - the product must have only fixed charges. - """ - - customer_plan_id: Required[str] - """The Metronome ID of the customer plan to add the charge to.""" - - description: Required[str] - - invoice_start_timestamp: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """The start_timestamp of the invoice to add the charge to.""" - - price: Required[float] - """The price of the charge. - - This price will match the currency on the invoice, e.g. USD cents. - """ - - quantity: Required[float] diff --git a/src/metronome/types/v1/customers/invoice_add_charge_response.py b/src/metronome/types/v1/customers/invoice_add_charge_response.py deleted file mode 100644 index 3cdcad38f..000000000 --- a/src/metronome/types/v1/customers/invoice_add_charge_response.py +++ /dev/null @@ -1,9 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel - -__all__ = ["InvoiceAddChargeResponse"] - - -class InvoiceAddChargeResponse(BaseModel): - pass diff --git a/src/metronome/types/v1/customers/invoice_list_breakdowns_params.py b/src/metronome/types/v1/customers/invoice_list_breakdowns_params.py deleted file mode 100644 index 404c6bea9..000000000 --- a/src/metronome/types/v1/customers/invoice_list_breakdowns_params.py +++ /dev/null @@ -1,58 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ...._utils import PropertyInfo - -__all__ = ["InvoiceListBreakdownsParams"] - - -class InvoiceListBreakdownsParams(TypedDict, total=False): - customer_id: Required[str] - - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp. - - Breakdowns will only be returned for time windows that end on or before this - time. - """ - - starting_on: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp. - - Breakdowns will only be returned for time windows that start on or after this - time. - """ - - credit_type_id: str - """Only return invoices for the specified credit type""" - - limit: int - """Max number of results that should be returned. - - For daily breakdowns, the response can return up to 35 days worth of breakdowns. - For hourly breakdowns, the response can return up to 24 hours. If there are more - results, a cursor to the next page is returned. - """ - - next_page: str - """Cursor that indicates where the next page of results should start.""" - - skip_zero_qty_line_items: bool - """If set, all zero quantity line items will be filtered out of the response""" - - sort: Literal["date_asc", "date_desc"] - """Invoice sort order by issued_at, e.g. - - date_asc or date_desc. Defaults to date_asc. - """ - - status: str - """Invoice status, e.g. DRAFT or FINALIZED""" - - window_size: Literal["HOUR", "DAY"] - """The granularity of the breakdowns to return. Defaults to day.""" diff --git a/src/metronome/types/v1/customers/invoice_list_breakdowns_response.py b/src/metronome/types/v1/customers/invoice_list_breakdowns_response.py deleted file mode 100644 index f8e8b972d..000000000 --- a/src/metronome/types/v1/customers/invoice_list_breakdowns_response.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from datetime import datetime - -from .invoice import Invoice - -__all__ = ["InvoiceListBreakdownsResponse"] - - -class InvoiceListBreakdownsResponse(Invoice): - breakdown_end_timestamp: datetime - - breakdown_start_timestamp: datetime diff --git a/src/metronome/types/v1/customers/invoice_list_params.py b/src/metronome/types/v1/customers/invoice_list_params.py deleted file mode 100644 index 0bed8644a..000000000 --- a/src/metronome/types/v1/customers/invoice_list_params.py +++ /dev/null @@ -1,49 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ...._utils import PropertyInfo - -__all__ = ["InvoiceListParams"] - - -class InvoiceListParams(TypedDict, total=False): - customer_id: Required[str] - - credit_type_id: str - """Only return invoices for the specified credit type""" - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """RFC 3339 timestamp (exclusive). - - Invoices will only be returned for billing periods that end before this time. - """ - - limit: int - """Max number of results that should be returned""" - - next_page: str - """Cursor that indicates where the next page of results should start.""" - - skip_zero_qty_line_items: bool - """If set, all zero quantity line items will be filtered out of the response""" - - sort: Literal["date_asc", "date_desc"] - """Invoice sort order by issued_at, e.g. - - date_asc or date_desc. Defaults to date_asc. - """ - - starting_on: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """RFC 3339 timestamp (inclusive). - - Invoices will only be returned for billing periods that start at or after this - time. - """ - - status: str - """Invoice status, e.g. DRAFT, FINALIZED, or VOID""" diff --git a/src/metronome/types/v1/customers/invoice_retrieve_params.py b/src/metronome/types/v1/customers/invoice_retrieve_params.py deleted file mode 100644 index c1fad581d..000000000 --- a/src/metronome/types/v1/customers/invoice_retrieve_params.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["InvoiceRetrieveParams"] - - -class InvoiceRetrieveParams(TypedDict, total=False): - customer_id: Required[str] - - invoice_id: Required[str] - - skip_zero_qty_line_items: bool - """If set, all zero quantity line items will be filtered out of the response""" diff --git a/src/metronome/types/v1/customers/invoice_retrieve_response.py b/src/metronome/types/v1/customers/invoice_retrieve_response.py deleted file mode 100644 index dc25179a6..000000000 --- a/src/metronome/types/v1/customers/invoice_retrieve_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .invoice import Invoice -from ...._models import BaseModel - -__all__ = ["InvoiceRetrieveResponse"] - - -class InvoiceRetrieveResponse(BaseModel): - data: Invoice diff --git a/src/metronome/types/v1/customers/named_schedule_retrieve_params.py b/src/metronome/types/v1/customers/named_schedule_retrieve_params.py deleted file mode 100644 index bea76e1ce..000000000 --- a/src/metronome/types/v1/customers/named_schedule_retrieve_params.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ...._utils import PropertyInfo - -__all__ = ["NamedScheduleRetrieveParams"] - - -class NamedScheduleRetrieveParams(TypedDict, total=False): - customer_id: Required[str] - """ID of the customer whose named schedule is to be retrieved""" - - schedule_name: Required[str] - """The identifier for the schedule to be retrieved""" - - covering_date: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """ - If provided, at most one schedule segment will be returned (the one that covers - this date). If not provided, all segments will be returned. - """ diff --git a/src/metronome/types/v1/customers/named_schedule_retrieve_response.py b/src/metronome/types/v1/customers/named_schedule_retrieve_response.py deleted file mode 100644 index d6b9cecc0..000000000 --- a/src/metronome/types/v1/customers/named_schedule_retrieve_response.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime - -from ...._models import BaseModel - -__all__ = ["NamedScheduleRetrieveResponse", "Data"] - - -class Data(BaseModel): - starting_at: datetime - - value: object - - ending_before: Optional[datetime] = None - - -class NamedScheduleRetrieveResponse(BaseModel): - data: List[Data] diff --git a/src/metronome/types/v1/customers/named_schedule_update_params.py b/src/metronome/types/v1/customers/named_schedule_update_params.py deleted file mode 100644 index ac4c5ac02..000000000 --- a/src/metronome/types/v1/customers/named_schedule_update_params.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ...._utils import PropertyInfo - -__all__ = ["NamedScheduleUpdateParams"] - - -class NamedScheduleUpdateParams(TypedDict, total=False): - customer_id: Required[str] - """ID of the customer whose named schedule is to be updated""" - - schedule_name: Required[str] - """The identifier for the schedule to be updated""" - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - value: Required[object] - """The value to set for the named schedule. - - The structure of this object is specific to the named schedule. - """ - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] diff --git a/src/metronome/types/v1/customers/plan_add_params.py b/src/metronome/types/v1/customers/plan_add_params.py deleted file mode 100644 index a8b9e6ff1..000000000 --- a/src/metronome/types/v1/customers/plan_add_params.py +++ /dev/null @@ -1,114 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ...._utils import PropertyInfo - -__all__ = ["PlanAddParams", "OverageRateAdjustment", "PriceAdjustment", "TrialSpec", "TrialSpecSpendingCap"] - - -class PlanAddParams(TypedDict, total=False): - customer_id: Required[str] - - plan_id: Required[str] - - starting_on: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp for when the plan becomes active for this customer. - - Must be at 0:00 UTC (midnight). - """ - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """RFC 3339 timestamp for when the plan ends (exclusive) for this customer. - - Must be at 0:00 UTC (midnight). - """ - - net_payment_terms_days: float - """Number of days after issuance of invoice after which the invoice is due (e.g. - - Net 30). - """ - - overage_rate_adjustments: Iterable[OverageRateAdjustment] - """ - An optional list of overage rates that override the rates of the original plan - configuration. These new rates will apply to all pricing ramps. - """ - - price_adjustments: Iterable[PriceAdjustment] - """A list of price adjustments can be applied on top of the pricing in the plans. - - See the - [price adjustments documentation](https://plans-docs.metronome.com/pricing/managing-plans/#price-adjustments) - for details. - """ - - trial_spec: TrialSpec - """A custom trial can be set for the customer's plan. - - See the - [trial configuration documentation](https://docs.metronome.com/provisioning/configure-trials/) - for details. - """ - - -class OverageRateAdjustment(TypedDict, total=False): - custom_credit_type_id: Required[str] - - fiat_currency_credit_type_id: Required[str] - - to_fiat_conversion_factor: Required[float] - """The overage cost in fiat currency for each credit of the custom credit type.""" - - -class PriceAdjustment(TypedDict, total=False): - adjustment_type: Required[Literal["percentage", "fixed", "override", "quantity"]] - - charge_id: Required[str] - - start_period: Required[float] - """Used in price ramps. - - Indicates how many billing periods pass before the charge applies. - """ - - quantity: float - """the overridden quantity for a fixed charge""" - - tier: float - """Used in pricing tiers. Indicates at what metric value the price applies.""" - - value: float - """The amount of change to a price. - - Percentage and fixed adjustments can be positive or negative. Percentage-based - adjustments should be decimals, e.g. -0.05 for a 5% discount. - """ - - -class TrialSpecSpendingCap(TypedDict, total=False): - amount: Required[float] - """The credit amount in the given denomination based on the credit type, e.g. - - US cents. - """ - - credit_type_id: Required[str] - """The credit type ID for the spending cap.""" - - -class TrialSpec(TypedDict, total=False): - """A custom trial can be set for the customer's plan. - - See the [trial configuration documentation](https://docs.metronome.com/provisioning/configure-trials/) for details. - """ - - length_in_days: Required[float] - """Length of the trial period in days.""" - - spending_cap: TrialSpecSpendingCap diff --git a/src/metronome/types/v1/customers/plan_add_response.py b/src/metronome/types/v1/customers/plan_add_response.py deleted file mode 100644 index 5d6eafd81..000000000 --- a/src/metronome/types/v1/customers/plan_add_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel -from ...shared.id import ID - -__all__ = ["PlanAddResponse"] - - -class PlanAddResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/customers/plan_end_params.py b/src/metronome/types/v1/customers/plan_end_params.py deleted file mode 100644 index ebd4f9442..000000000 --- a/src/metronome/types/v1/customers/plan_end_params.py +++ /dev/null @@ -1,38 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ...._utils import PropertyInfo - -__all__ = ["PlanEndParams"] - - -class PlanEndParams(TypedDict, total=False): - customer_id: Required[str] - - customer_plan_id: Required[str] - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """RFC 3339 timestamp for when the plan ends (exclusive) for this customer. - - Must be at 0:00 UTC (midnight). If not provided, the plan end date will be - cleared. - """ - - void_invoices: bool - """If true, plan end date can be before the last finalized invoice date. - - Any invoices generated after the plan end date will be voided. - """ - - void_stripe_invoices: bool - """Only applicable when void_invoices is set to true. - - If true, for every invoice that is voided we will also attempt to void/delete - the stripe invoice (if any). Stripe invoices will be voided if finalized or - deleted if still in draft state. - """ diff --git a/src/metronome/types/v1/customers/plan_end_response.py b/src/metronome/types/v1/customers/plan_end_response.py deleted file mode 100644 index 82d5f9062..000000000 --- a/src/metronome/types/v1/customers/plan_end_response.py +++ /dev/null @@ -1,9 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel - -__all__ = ["PlanEndResponse"] - - -class PlanEndResponse(BaseModel): - pass diff --git a/src/metronome/types/v1/customers/plan_list_params.py b/src/metronome/types/v1/customers/plan_list_params.py deleted file mode 100644 index 5d266c5c4..000000000 --- a/src/metronome/types/v1/customers/plan_list_params.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["PlanListParams"] - - -class PlanListParams(TypedDict, total=False): - customer_id: Required[str] - - limit: int - """Max number of results that should be returned""" - - next_page: str - """Cursor that indicates where the next page of results should start.""" diff --git a/src/metronome/types/v1/customers/plan_list_price_adjustments_params.py b/src/metronome/types/v1/customers/plan_list_price_adjustments_params.py deleted file mode 100644 index 24d422262..000000000 --- a/src/metronome/types/v1/customers/plan_list_price_adjustments_params.py +++ /dev/null @@ -1,19 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["PlanListPriceAdjustmentsParams"] - - -class PlanListPriceAdjustmentsParams(TypedDict, total=False): - customer_id: Required[str] - - customer_plan_id: Required[str] - - limit: int - """Max number of results that should be returned""" - - next_page: str - """Cursor that indicates where the next page of results should start.""" diff --git a/src/metronome/types/v1/customers/plan_list_price_adjustments_response.py b/src/metronome/types/v1/customers/plan_list_price_adjustments_response.py deleted file mode 100644 index 487de8bbe..000000000 --- a/src/metronome/types/v1/customers/plan_list_price_adjustments_response.py +++ /dev/null @@ -1,32 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["PlanListPriceAdjustmentsResponse", "Price"] - - -class Price(BaseModel): - adjustment_type: Literal["fixed", "quantity", "percentage", "override"] - """Determines how the value will be applied.""" - - quantity: Optional[float] = None - - tier: Optional[float] = None - """Used in pricing tiers. Indicates at what metric value the price applies.""" - - value: Optional[float] = None - - -class PlanListPriceAdjustmentsResponse(BaseModel): - charge_id: str - - charge_type: Literal["usage", "fixed", "composite", "minimum", "seat"] - - prices: List[Price] - - start_period: float - - quantity: Optional[float] = None diff --git a/src/metronome/types/v1/customers/plan_list_response.py b/src/metronome/types/v1/customers/plan_list_response.py deleted file mode 100644 index 4380f8656..000000000 --- a/src/metronome/types/v1/customers/plan_list_response.py +++ /dev/null @@ -1,46 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from datetime import datetime - -from ...._models import BaseModel -from ...shared.credit_type_data import CreditTypeData - -__all__ = ["PlanListResponse", "TrialInfo", "TrialInfoSpendingCap"] - - -class TrialInfoSpendingCap(BaseModel): - amount: float - - amount_remaining: float - - credit_type: CreditTypeData - - -class TrialInfo(BaseModel): - ending_before: datetime - - spending_caps: List[TrialInfoSpendingCap] - - -class PlanListResponse(BaseModel): - id: str - """the ID of the customer plan""" - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - plan_description: str - - plan_id: str - """the ID of the plan""" - - plan_name: str - - starting_on: datetime - - ending_before: Optional[datetime] = None - - net_payment_terms_days: Optional[float] = None - - trial_info: Optional[TrialInfo] = None diff --git a/src/metronome/types/v1/dashboard_get_embeddable_url_params.py b/src/metronome/types/v1/dashboard_get_embeddable_url_params.py deleted file mode 100644 index 106414a1b..000000000 --- a/src/metronome/types/v1/dashboard_get_embeddable_url_params.py +++ /dev/null @@ -1,76 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Iterable -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["DashboardGetEmbeddableURLParams", "BmGroupKeyOverride", "ColorOverride", "DashboardOption"] - - -class DashboardGetEmbeddableURLParams(TypedDict, total=False): - customer_id: Required[str] - - dashboard: Required[Literal["invoices", "usage", "credits", "commits_and_credits"]] - """The type of dashboard to retrieve.""" - - bm_group_key_overrides: Iterable[BmGroupKeyOverride] - """Optional list of billable metric group key overrides""" - - color_overrides: Iterable[ColorOverride] - """Optional list of colors to override""" - - dashboard_options: Iterable[DashboardOption] - """Optional dashboard specific options""" - - -class BmGroupKeyOverride(TypedDict, total=False): - group_key_name: Required[str] - """The name of the billable metric group key.""" - - display_name: str - """The display name for the billable metric group key""" - - value_display_names: Dict[str, object] - """ - pairs of the billable metric group key values and their display - names. e.g. {"a": "Asia", "b": "Euro"} - """ - - -class ColorOverride(TypedDict, total=False): - name: Literal[ - "Gray_dark", - "Gray_medium", - "Gray_light", - "Gray_extralight", - "White", - "Primary_medium", - "Primary_light", - "UsageLine_0", - "UsageLine_1", - "UsageLine_2", - "UsageLine_3", - "UsageLine_4", - "UsageLine_5", - "UsageLine_6", - "UsageLine_7", - "UsageLine_8", - "UsageLine_9", - "Primary_green", - "Primary_red", - "Progress_bar", - "Progress_bar_background", - ] - """The color to override""" - - value: str - """Hex value representation of the color""" - - -class DashboardOption(TypedDict, total=False): - key: Required[str] - """The option key name""" - - value: Required[str] - """The option value""" diff --git a/src/metronome/types/v1/dashboard_get_embeddable_url_response.py b/src/metronome/types/v1/dashboard_get_embeddable_url_response.py deleted file mode 100644 index f111d310e..000000000 --- a/src/metronome/types/v1/dashboard_get_embeddable_url_response.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ..._models import BaseModel - -__all__ = ["DashboardGetEmbeddableURLResponse", "Data"] - - -class Data(BaseModel): - url: Optional[str] = None - - -class DashboardGetEmbeddableURLResponse(BaseModel): - data: Data diff --git a/src/metronome/types/v1/invoice_regenerate_params.py b/src/metronome/types/v1/invoice_regenerate_params.py deleted file mode 100644 index fba80ec03..000000000 --- a/src/metronome/types/v1/invoice_regenerate_params.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["InvoiceRegenerateParams"] - - -class InvoiceRegenerateParams(TypedDict, total=False): - id: Required[str] - """The invoice id to regenerate""" diff --git a/src/metronome/types/v1/invoice_regenerate_response.py b/src/metronome/types/v1/invoice_regenerate_response.py deleted file mode 100644 index 4a6afb144..000000000 --- a/src/metronome/types/v1/invoice_regenerate_response.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ..._models import BaseModel - -__all__ = ["InvoiceRegenerateResponse", "Data"] - - -class Data(BaseModel): - id: str - """The new invoice id""" - - -class InvoiceRegenerateResponse(BaseModel): - data: Optional[Data] = None diff --git a/src/metronome/types/v1/invoice_void_params.py b/src/metronome/types/v1/invoice_void_params.py deleted file mode 100644 index 8a876c8cf..000000000 --- a/src/metronome/types/v1/invoice_void_params.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["InvoiceVoidParams"] - - -class InvoiceVoidParams(TypedDict, total=False): - id: Required[str] - """The invoice id to void""" diff --git a/src/metronome/types/v1/invoice_void_response.py b/src/metronome/types/v1/invoice_void_response.py deleted file mode 100644 index 46ac15b30..000000000 --- a/src/metronome/types/v1/invoice_void_response.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ..._models import BaseModel - -__all__ = ["InvoiceVoidResponse", "Data"] - - -class Data(BaseModel): - id: str - - -class InvoiceVoidResponse(BaseModel): - data: Optional[Data] = None diff --git a/src/metronome/types/v1/package_archive_params.py b/src/metronome/types/v1/package_archive_params.py deleted file mode 100644 index cbe732d0e..000000000 --- a/src/metronome/types/v1/package_archive_params.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["PackageArchiveParams"] - - -class PackageArchiveParams(TypedDict, total=False): - package_id: Required[str] - """ID of the package to archive""" diff --git a/src/metronome/types/v1/package_archive_response.py b/src/metronome/types/v1/package_archive_response.py deleted file mode 100644 index e0c532b1d..000000000 --- a/src/metronome/types/v1/package_archive_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel -from ..shared.id import ID - -__all__ = ["PackageArchiveResponse"] - - -class PackageArchiveResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/package_create_params.py b/src/metronome/types/v1/package_create_params.py deleted file mode 100644 index 090ed1b1b..000000000 --- a/src/metronome/types/v1/package_create_params.py +++ /dev/null @@ -1,1065 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ..._types import SequenceNotStr -from ..._utils import PropertyInfo -from ..shared_params.tier import Tier -from ..shared_params.commit_specifier_input import CommitSpecifierInput -from ..shared_params.spend_threshold_configuration import SpendThresholdConfiguration -from ..shared_params.prepaid_balance_threshold_configuration import PrepaidBalanceThresholdConfiguration - -__all__ = [ - "PackageCreateParams", - "Alias", - "Commit", - "CommitAccessSchedule", - "CommitAccessScheduleScheduleItem", - "CommitAccessScheduleScheduleItemDuration", - "CommitAccessScheduleScheduleItemStartingAtOffset", - "CommitInvoiceSchedule", - "CommitInvoiceScheduleScheduleItem", - "CommitInvoiceScheduleScheduleItemDateOffset", - "Credit", - "CreditAccessSchedule", - "CreditAccessScheduleScheduleItem", - "CreditAccessScheduleScheduleItemDuration", - "CreditAccessScheduleScheduleItemStartingAtOffset", - "Duration", - "Override", - "OverrideOverrideSpecifier", - "OverrideStartingAtOffset", - "OverrideDuration", - "OverrideOverwriteRate", - "OverrideTier", - "RecurringCommit", - "RecurringCommitAccessAmount", - "RecurringCommitCommitDuration", - "RecurringCommitStartingAtOffset", - "RecurringCommitDuration", - "RecurringCommitInvoiceAmount", - "RecurringCommitSubscriptionConfig", - "RecurringCommitSubscriptionConfigApplySeatIncreaseConfig", - "RecurringCredit", - "RecurringCreditAccessAmount", - "RecurringCreditCommitDuration", - "RecurringCreditStartingAtOffset", - "RecurringCreditDuration", - "RecurringCreditSubscriptionConfig", - "RecurringCreditSubscriptionConfigApplySeatIncreaseConfig", - "ScheduledCharge", - "ScheduledChargeSchedule", - "ScheduledChargeScheduleScheduleItem", - "ScheduledChargeScheduleScheduleItemDateOffset", - "Subscription", - "SubscriptionProration", - "SubscriptionSubscriptionRate", - "SubscriptionDuration", - "SubscriptionSeatConfig", - "SubscriptionStartingAtOffset", - "UsageStatementSchedule", - "UsageStatementScheduleInvoiceGenerationStartingAtOffset", -] - - -class PackageCreateParams(TypedDict, total=False): - name: Required[str] - - aliases: Iterable[Alias] - """Reference this alias when creating a contract. - - If the same alias is assigned to multiple packages, it will reference the - package to which it was most recently assigned. It is not exposed to end - customers. - """ - - billing_anchor_date: Literal["contract_start_date", "first_billing_period"] - - billing_provider: Literal["aws_marketplace", "azure_marketplace", "gcp_marketplace", "stripe", "netsuite"] - - commits: Iterable[Commit] - - contract_name: str - - credits: Iterable[Credit] - - delivery_method: Literal["direct_to_billing_provider", "aws_sqs", "tackle", "aws_sns"] - - duration: Duration - - multiplier_override_prioritization: Literal["LOWEST_MULTIPLIER", "EXPLICIT"] - """ - Defaults to LOWEST_MULTIPLIER, which applies the greatest discount to list - prices automatically. EXPLICIT prioritization requires specifying priorities for - each multiplier; the one with the lowest priority value will be prioritized - first. If tiered overrides are used, prioritization must be explicit. - """ - - net_payment_terms_days: float - - overrides: Iterable[Override] - - prepaid_balance_threshold_configuration: PrepaidBalanceThresholdConfiguration - - rate_card_alias: str - """ - Selects the rate card linked to the specified alias as of the contract's start - date. - """ - - rate_card_id: str - - recurring_commits: Iterable[RecurringCommit] - - recurring_credits: Iterable[RecurringCredit] - - scheduled_charges: Iterable[ScheduledCharge] - - scheduled_charges_on_usage_invoices: Literal["ALL"] - """ - Determines which scheduled and commit charges to consolidate onto the Contract's - usage invoice. The charge's `timestamp` must match the usage invoice's - `ending_before` date for consolidation to occur. This field cannot be modified - after a Contract has been created. If this field is omitted, charges will appear - on a separate invoice from usage charges. - """ - - spend_threshold_configuration: SpendThresholdConfiguration - - subscriptions: Iterable[Subscription] - - uniqueness_key: str - """Prevents the creation of duplicates. - - If a request to create a record is made with a previously used uniqueness key, a - new record will not be created and the request will fail with a 409 error. - """ - - usage_statement_schedule: UsageStatementSchedule - - -class Alias(TypedDict, total=False): - name: Required[str] - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - - starting_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - - -class CommitAccessScheduleScheduleItemDuration(TypedDict, total=False): - """Offset relative to the start of this segment indicating when it should end.""" - - unit: Required[Literal["DAYS", "WEEKS", "MONTHS", "YEARS"]] - - value: Required[int] - - -class CommitAccessScheduleScheduleItemStartingAtOffset(TypedDict, total=False): - """ - Date relative to the contract start date indicating the start of this schedule segment. - """ - - unit: Required[Literal["DAYS", "WEEKS", "MONTHS", "YEARS"]] - - value: Required[int] - - -class CommitAccessScheduleScheduleItem(TypedDict, total=False): - amount: Required[float] - - duration: Required[CommitAccessScheduleScheduleItemDuration] - """Offset relative to the start of this segment indicating when it should end.""" - - starting_at_offset: Required[CommitAccessScheduleScheduleItemStartingAtOffset] - """ - Date relative to the contract start date indicating the start of this schedule - segment. - """ - - -class CommitAccessSchedule(TypedDict, total=False): - """Required: Schedule for distributing the commit to the customer. - - For "POSTPAID" commits only one schedule item is allowed and amount must match invoice_schedule total. - """ - - schedule_items: Required[Iterable[CommitAccessScheduleScheduleItem]] - - credit_type_id: str - """Defaults to USD (cents) if not passed""" - - -class CommitInvoiceScheduleScheduleItemDateOffset(TypedDict, total=False): - """Date relative to the contract start date.""" - - unit: Required[Literal["DAYS", "WEEKS", "MONTHS", "YEARS"]] - - value: Required[int] - - -class CommitInvoiceScheduleScheduleItem(TypedDict, total=False): - date_offset: Required[CommitInvoiceScheduleScheduleItemDateOffset] - """Date relative to the contract start date.""" - - quantity: Required[float] - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount. - """ - - unit_price: Required[float] - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount. - """ - - -class CommitInvoiceSchedule(TypedDict, total=False): - """ - Required for "POSTPAID" commits: the true up invoice will be generated at this time and only one schedule item is allowed; the total must match access_schedule amount. Optional for "PREPAID" commits: if not provided, this will be a "complimentary" commit with no invoice. - """ - - schedule_items: Required[Iterable[CommitInvoiceScheduleScheduleItem]] - """Either provide amount or provide both unit_price and quantity.""" - - credit_type_id: str - """Defaults to USD (cents) if not passed.""" - - do_not_invoice: bool - """If true, this schedule will not generate an invoice.""" - - -class Commit(TypedDict, total=False): - access_schedule: Required[CommitAccessSchedule] - """Required: Schedule for distributing the commit to the customer. - - For "POSTPAID" commits only one schedule item is allowed and amount must match - invoice_schedule total. - """ - - product_id: Required[str] - - type: Required[Literal["PREPAID", "POSTPAID"]] - - applicable_product_ids: SequenceNotStr[str] - """Which products the commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - applicable_product_tags: SequenceNotStr[str] - """Which tags the commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: str - """Used only in UI/API. It is not exposed to end customers.""" - - invoice_schedule: CommitInvoiceSchedule - """ - Required for "POSTPAID" commits: the true up invoice will be generated at this - time and only one schedule item is allowed; the total must match access_schedule - amount. Optional for "PREPAID" commits: if not provided, this will be a - "complimentary" commit with no invoice. - """ - - name: str - """displayed on invoices""" - - priority: float - """ - If multiple commits are applicable, the one with the lower priority will apply - first. - """ - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - - rollover_fraction: float - """Fraction of unused segments that will be rolled over. Must be between 0 and 1.""" - - specifiers: Iterable[CommitSpecifierInput] - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - """ - - temporary_id: str - """ - A temporary ID for the commit that can be used to reference the commit for - commit specific overrides. - """ - - -class CreditAccessScheduleScheduleItemDuration(TypedDict, total=False): - """Offset relative to the start of this segment indicating when it should end.""" - - unit: Required[Literal["DAYS", "WEEKS", "MONTHS", "YEARS"]] - - value: Required[int] - - -class CreditAccessScheduleScheduleItemStartingAtOffset(TypedDict, total=False): - """ - Date relative to the contract start date indicating the start of this schedule segment. - """ - - unit: Required[Literal["DAYS", "WEEKS", "MONTHS", "YEARS"]] - - value: Required[int] - - -class CreditAccessScheduleScheduleItem(TypedDict, total=False): - amount: Required[float] - - duration: Required[CreditAccessScheduleScheduleItemDuration] - """Offset relative to the start of this segment indicating when it should end.""" - - starting_at_offset: Required[CreditAccessScheduleScheduleItemStartingAtOffset] - """ - Date relative to the contract start date indicating the start of this schedule - segment. - """ - - -class CreditAccessSchedule(TypedDict, total=False): - """Schedule for distributing the credit to the customer.""" - - schedule_items: Required[Iterable[CreditAccessScheduleScheduleItem]] - - credit_type_id: str - """Defaults to USD (cents) if not passed""" - - -class Credit(TypedDict, total=False): - access_schedule: Required[CreditAccessSchedule] - """Schedule for distributing the credit to the customer.""" - - product_id: Required[str] - - applicable_product_ids: SequenceNotStr[str] - """Which products the credit applies to. - - If both applicable_product_ids and applicable_product_tags are not provided, the - credit applies to all products. - """ - - applicable_product_tags: SequenceNotStr[str] - """Which tags the credit applies to. - - If both applicable_product_ids and applicable_product_tags are not provided, the - credit applies to all products. - """ - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: str - """Used only in UI/API. It is not exposed to end customers.""" - - name: str - """displayed on invoices""" - - priority: float - """ - If multiple credits are applicable, the one with the lower priority will apply - first. - """ - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - - specifiers: Iterable[CommitSpecifierInput] - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - """ - - -class Duration(TypedDict, total=False): - unit: Required[Literal["DAYS", "WEEKS", "MONTHS", "YEARS"]] - - value: Required[int] - - -class OverrideOverrideSpecifier(TypedDict, total=False): - billing_frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"] - - commit_ids: SequenceNotStr[str] - """Can only be used for commit specific overrides. - - Must be used in conjunction with one of `product_id`, `product_tags`, - `pricing_group_values`, or `presentation_group_values`. If provided, the - override will only apply to the specified commits. If not provided, the override - will apply to all commits. - """ - - presentation_group_values: Dict[str, str] - """A map of group names to values. - - The override will only apply to line items with the specified presentation group - values. - """ - - pricing_group_values: Dict[str, str] - """A map of pricing group names to values. - - The override will only apply to products with the specified pricing group - values. - """ - - product_id: str - """If provided, the override will only apply to the product with the specified ID.""" - - product_tags: SequenceNotStr[str] - """ - If provided, the override will only apply to products with all the specified - tags. - """ - - recurring_commit_ids: SequenceNotStr[str] - """Can only be used for commit specific overrides. - - Must be used in conjunction with one of `product_id`, `product_tags`, - `pricing_group_values`, or `presentation_group_values`. If provided, the - override will only apply to commits created by the specified recurring commit - ids. - """ - - recurring_credit_ids: SequenceNotStr[str] - """Can only be used for commit specific overrides. - - Must be used in conjunction with one of `product_id`, `product_tags`, - `pricing_group_values`, or `presentation_group_values`. If provided, the - override will only apply to credits created by the specified recurring credit - ids. - """ - - -class OverrideStartingAtOffset(TypedDict, total=False): - """ - Offset relative to contract start date indicating when the override will start applying (inclusive) - """ - - unit: Required[Literal["DAYS", "WEEKS", "MONTHS", "YEARS"]] - - value: Required[int] - - -class OverrideDuration(TypedDict, total=False): - """ - Offset relative to override start indicating when the override will stop applying (exclusive) - """ - - unit: Required[Literal["DAYS", "WEEKS", "MONTHS", "YEARS"]] - - value: Required[int] - - -class OverrideOverwriteRate(TypedDict, total=False): - """Required for OVERWRITE type.""" - - rate_type: Required[Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "TIERED", "TIERED_PERCENTAGE", "CUSTOM"]] - - credit_type_id: str - - custom_rate: Dict[str, object] - """Only set for CUSTOM rate_type. - - This field is interpreted by custom rate processors. - """ - - is_prorated: bool - """Default proration configuration. - - Only valid for SUBSCRIPTION rate_type. Must be set to true. - """ - - price: float - """Default price. - - For FLAT rate_type, this must be >=0. For PERCENTAGE rate_type, this is a - decimal fraction, e.g. use 0.1 for 10%; this must be >=0 and <=1. - """ - - quantity: float - """Default quantity. For SUBSCRIPTION rate_type, this must be >=0.""" - - tiers: Iterable[Tier] - """Only set for TIERED rate_type.""" - - -class OverrideTier(TypedDict, total=False): - multiplier: Required[float] - - size: float - - -class Override(TypedDict, total=False): - override_specifiers: Required[Iterable[OverrideOverrideSpecifier]] - """Specifies which products the override will apply to.""" - - starting_at_offset: Required[OverrideStartingAtOffset] - """ - Offset relative to contract start date indicating when the override will start - applying (inclusive) - """ - - duration: OverrideDuration - """ - Offset relative to override start indicating when the override will stop - applying (exclusive) - """ - - entitled: bool - - is_commit_specific: bool - """Indicates whether the override should only apply to commits. - - Defaults to `false`. If `true`, you can specify relevant commits in - `override_specifiers` by passing `commit_ids`. if you do not specify - `commit_ids`, then the override will apply when consuming any prepaid or - postpaid commit. - """ - - multiplier: float - """Required for MULTIPLIER type. Must be >=0.""" - - overwrite_rate: OverrideOverwriteRate - """Required for OVERWRITE type.""" - - priority: float - """Required for EXPLICIT multiplier prioritization scheme and all TIERED overrides. - - Under EXPLICIT prioritization, overwrites are prioritized first, and then tiered - and multiplier overrides are prioritized by their priority value (lowest first). - Must be > 0. - """ - - target: Literal["COMMIT_RATE", "LIST_RATE"] - """Indicates whether the override applies to commit rates or list rates. - - Can only be used for overrides that have `is_commit_specific` set to `true`. - Defaults to `"LIST_RATE"`. - """ - - tiers: Iterable[OverrideTier] - """Required for TIERED type. Must have at least one tier.""" - - type: Literal["OVERWRITE", "MULTIPLIER", "TIERED"] - """Overwrites are prioritized over multipliers and tiered overrides.""" - - -class RecurringCommitAccessAmount(TypedDict, total=False): - """The amount of commit to grant.""" - - credit_type_id: Required[str] - - unit_price: Required[float] - - quantity: float - """ - This field is required unless a subscription is attached via - `subscription_config`. - """ - - -class RecurringCommitCommitDuration(TypedDict, total=False): - """Defines the length of the access schedule for each created commit/credit. - - The value represents the number of units. Unit defaults to "PERIODS", where the length of a period is determined by the recurrence_frequency. - """ - - value: Required[float] - - unit: Literal["PERIODS"] - - -class RecurringCommitStartingAtOffset(TypedDict, total=False): - """ - Offset relative to the contract start date that determines the start time for the first commit - """ - - unit: Required[Literal["DAYS", "WEEKS", "MONTHS", "YEARS"]] - - value: Required[int] - - -class RecurringCommitDuration(TypedDict, total=False): - """ - Offset relative to the recurring credit start that determines when the contract will stop creating recurring commits. optional - """ - - unit: Required[Literal["DAYS", "WEEKS", "MONTHS", "YEARS"]] - - value: Required[int] - - -class RecurringCommitInvoiceAmount(TypedDict, total=False): - """The amount the customer should be billed for the commit. Not required.""" - - credit_type_id: Required[str] - - quantity: Required[float] - - unit_price: Required[float] - - -class RecurringCommitSubscriptionConfigApplySeatIncreaseConfig(TypedDict, total=False): - is_prorated: Required[bool] - """Indicates whether a mid-period seat increase should be prorated.""" - - -class RecurringCommitSubscriptionConfig(TypedDict, total=False): - """Attach a subscription to the recurring commit/credit.""" - - apply_seat_increase_config: Required[RecurringCommitSubscriptionConfigApplySeatIncreaseConfig] - - subscription_id: Required[str] - """ID of the subscription to configure on the recurring commit/credit.""" - - allocation: Literal["INDIVIDUAL", "POOLED"] - """If set to POOLED, allocation added per seat is pooled across the account. - - If set to INDIVIDUAL, each seat in the subscription will have its own - allocation. - """ - - -class RecurringCommit(TypedDict, total=False): - access_amount: Required[RecurringCommitAccessAmount] - """The amount of commit to grant.""" - - commit_duration: Required[RecurringCommitCommitDuration] - """Defines the length of the access schedule for each created commit/credit. - - The value represents the number of units. Unit defaults to "PERIODS", where the - length of a period is determined by the recurrence_frequency. - """ - - priority: Required[float] - """Will be passed down to the individual commits""" - - product_id: Required[str] - - starting_at_offset: Required[RecurringCommitStartingAtOffset] - """ - Offset relative to the contract start date that determines the start time for - the first commit - """ - - applicable_product_ids: SequenceNotStr[str] - """Will be passed down to the individual commits""" - - applicable_product_tags: SequenceNotStr[str] - """Will be passed down to the individual commits""" - - description: str - """Will be passed down to the individual commits""" - - duration: RecurringCommitDuration - """ - Offset relative to the recurring credit start that determines when the contract - will stop creating recurring commits. optional - """ - - invoice_amount: RecurringCommitInvoiceAmount - """The amount the customer should be billed for the commit. Not required.""" - - name: str - """displayed on invoices. will be passed through to the individual commits""" - - proration: Literal["NONE", "FIRST", "LAST", "FIRST_AND_LAST"] - """Determines whether the first and last commit will be prorated. - - If not provided, the default is FIRST_AND_LAST (i.e. prorate both the first and - last commits). - """ - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - """Whether the created commits will use the commit rate or list rate""" - - recurrence_frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"] - """The frequency at which the recurring commits will be created. - - If not provided: - The commits will be created on the usage invoice frequency. - If provided: - The period defined in the duration will correspond to this - frequency. - Commits will be created aligned with the recurring commit's - starting_at rather than the usage invoice dates. - """ - - rollover_fraction: float - """Will be passed down to the individual commits. - - This controls how much of an individual unexpired commit will roll over upon - contract transition. Must be between 0 and 1. - """ - - specifiers: Iterable[CommitSpecifierInput] - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - """ - - subscription_config: RecurringCommitSubscriptionConfig - """Attach a subscription to the recurring commit/credit.""" - - temporary_id: str - """ - A temporary ID that can be used to reference the recurring commit for commit - specific overrides. - """ - - -class RecurringCreditAccessAmount(TypedDict, total=False): - """The amount of commit to grant.""" - - credit_type_id: Required[str] - - unit_price: Required[float] - - quantity: float - """ - This field is required unless a subscription is attached via - `subscription_config`. - """ - - -class RecurringCreditCommitDuration(TypedDict, total=False): - """Defines the length of the access schedule for each created commit/credit. - - The value represents the number of units. Unit defaults to "PERIODS", where the length of a period is determined by the recurrence_frequency. - """ - - value: Required[float] - - unit: Literal["PERIODS"] - - -class RecurringCreditStartingAtOffset(TypedDict, total=False): - """ - Offset relative to the contract start date that determines the start time for the first commit - """ - - unit: Required[Literal["DAYS", "WEEKS", "MONTHS", "YEARS"]] - - value: Required[int] - - -class RecurringCreditDuration(TypedDict, total=False): - """ - Offset relative to the recurring credit start that determines when the contract will stop creating recurring commits. optional - """ - - unit: Required[Literal["DAYS", "WEEKS", "MONTHS", "YEARS"]] - - value: Required[int] - - -class RecurringCreditSubscriptionConfigApplySeatIncreaseConfig(TypedDict, total=False): - is_prorated: Required[bool] - """Indicates whether a mid-period seat increase should be prorated.""" - - -class RecurringCreditSubscriptionConfig(TypedDict, total=False): - """Attach a subscription to the recurring commit/credit.""" - - apply_seat_increase_config: Required[RecurringCreditSubscriptionConfigApplySeatIncreaseConfig] - - subscription_id: Required[str] - """ID of the subscription to configure on the recurring commit/credit.""" - - allocation: Literal["INDIVIDUAL", "POOLED"] - """If set to POOLED, allocation added per seat is pooled across the account. - - If set to INDIVIDUAL, each seat in the subscription will have its own - allocation. - """ - - -class RecurringCredit(TypedDict, total=False): - access_amount: Required[RecurringCreditAccessAmount] - """The amount of commit to grant.""" - - commit_duration: Required[RecurringCreditCommitDuration] - """Defines the length of the access schedule for each created commit/credit. - - The value represents the number of units. Unit defaults to "PERIODS", where the - length of a period is determined by the recurrence_frequency. - """ - - priority: Required[float] - """Will be passed down to the individual commits""" - - product_id: Required[str] - - starting_at_offset: Required[RecurringCreditStartingAtOffset] - """ - Offset relative to the contract start date that determines the start time for - the first commit - """ - - applicable_product_ids: SequenceNotStr[str] - """Will be passed down to the individual commits""" - - applicable_product_tags: SequenceNotStr[str] - """Will be passed down to the individual commits""" - - description: str - """Will be passed down to the individual commits""" - - duration: RecurringCreditDuration - """ - Offset relative to the recurring credit start that determines when the contract - will stop creating recurring commits. optional - """ - - name: str - """displayed on invoices. will be passed through to the individual commits""" - - proration: Literal["NONE", "FIRST", "LAST", "FIRST_AND_LAST"] - """Determines whether the first and last commit will be prorated. - - If not provided, the default is FIRST_AND_LAST (i.e. prorate both the first and - last commits). - """ - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - """Whether the created commits will use the commit rate or list rate""" - - recurrence_frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"] - """The frequency at which the recurring commits will be created. - - If not provided: - The commits will be created on the usage invoice frequency. - If provided: - The period defined in the duration will correspond to this - frequency. - Commits will be created aligned with the recurring commit's - starting_at rather than the usage invoice dates. - """ - - rollover_fraction: float - """Will be passed down to the individual commits. - - This controls how much of an individual unexpired commit will roll over upon - contract transition. Must be between 0 and 1. - """ - - specifiers: Iterable[CommitSpecifierInput] - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - """ - - subscription_config: RecurringCreditSubscriptionConfig - """Attach a subscription to the recurring commit/credit.""" - - temporary_id: str - """ - A temporary ID that can be used to reference the recurring commit for commit - specific overrides. - """ - - -class ScheduledChargeScheduleScheduleItemDateOffset(TypedDict, total=False): - """Date relative to the contract start date.""" - - unit: Required[Literal["DAYS", "WEEKS", "MONTHS", "YEARS"]] - - value: Required[int] - - -class ScheduledChargeScheduleScheduleItem(TypedDict, total=False): - date_offset: Required[ScheduledChargeScheduleScheduleItemDateOffset] - """Date relative to the contract start date.""" - - quantity: Required[float] - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount. - """ - - unit_price: Required[float] - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount. - """ - - -class ScheduledChargeSchedule(TypedDict, total=False): - """Must provide schedule_items.""" - - schedule_items: Required[Iterable[ScheduledChargeScheduleScheduleItem]] - """Either provide amount or provide both unit_price and quantity.""" - - credit_type_id: str - """Defaults to USD (cents) if not passed.""" - - -class ScheduledCharge(TypedDict, total=False): - product_id: Required[str] - - schedule: Required[ScheduledChargeSchedule] - """Must provide schedule_items.""" - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - name: str - """displayed on invoices""" - - -class SubscriptionProration(TypedDict, total=False): - invoice_behavior: Literal["BILL_IMMEDIATELY", "BILL_ON_NEXT_COLLECTION_DATE"] - """Indicates how mid-period quantity adjustments are invoiced. - - **BILL_IMMEDIATELY**: Only available when collection schedule is `ADVANCE`. The - quantity increase will be billed immediately on the scheduled date. - **BILL_ON_NEXT_COLLECTION_DATE**: The quantity increase will be billed for - in-arrears at the end of the period. - """ - - is_prorated: bool - """Indicates if the partial period will be prorated or charged a full amount.""" - - -class SubscriptionSubscriptionRate(TypedDict, total=False): - billing_frequency: Required[Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"]] - """Frequency to bill subscription with. - - Together with product_id, must match existing rate on the rate card. - """ - - product_id: Required[str] - """Must be subscription type product""" - - -class SubscriptionDuration(TypedDict, total=False): - """Lifetime of the subscription from its start. - - If not provided, subscription inherits contract end date. - """ - - unit: Required[Literal["DAYS", "WEEKS", "MONTHS", "YEARS"]] - - value: Required[int] - - -class SubscriptionSeatConfig(TypedDict, total=False): - seat_group_key: Required[str] - """ - The property name, sent on usage events, that identifies the seat ID associated - with the usage event. For example, the property name might be seat_id or - user_id. The property must be set as a group key on billable metrics and a - presentation/pricing group key on contract products. This allows linked - recurring credits with an allocation per seat to be consumed by only one seat's - usage. - """ - - initial_unassigned_seats: float - """The initial amount of unassigned seats on this subscription.""" - - -class SubscriptionStartingAtOffset(TypedDict, total=False): - """ - Relative date from contract start date corresponding to the inclusive start time for the subscription. If not provided, defaults to contract start date - """ - - unit: Required[Literal["DAYS", "WEEKS", "MONTHS", "YEARS"]] - - value: Required[int] - - -class Subscription(TypedDict, total=False): - collection_schedule: Required[Literal["ADVANCE", "ARREARS"]] - - proration: Required[SubscriptionProration] - - subscription_rate: Required[SubscriptionSubscriptionRate] - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: str - - duration: SubscriptionDuration - """Lifetime of the subscription from its start. - - If not provided, subscription inherits contract end date. - """ - - initial_quantity: float - """The initial quantity for the subscription. - - It must be non-negative value. Required if quantity_management_mode is - QUANTITY_ONLY. - """ - - name: str - - quantity_management_mode: Literal["SEAT_BASED", "QUANTITY_ONLY"] - """Determines how the subscription's quantity is controlled. - - Defaults to QUANTITY_ONLY. **QUANTITY_ONLY**: The subscription quantity is - specified directly on the subscription. `initial_quantity` must be provided with - this option. Compatible with recurring commits/credits that use POOLED - allocation. **SEAT_BASED**: Use when you want to pass specific seat identifiers - (e.g. add user_123) to increment and decrement a subscription quantity, rather - than directly providing the quantity. You must use a **SEAT_BASED** subscription - to use a linked recurring credit with an allocation per seat. `seat_config` must - be provided with this option. - """ - - seat_config: SubscriptionSeatConfig - - starting_at_offset: SubscriptionStartingAtOffset - """ - Relative date from contract start date corresponding to the inclusive start time - for the subscription. If not provided, defaults to contract start date - """ - - temporary_id: str - """ - A temporary ID used to reference the subscription in recurring commit/credit - subscription configs created within the same payload. - """ - - -class UsageStatementScheduleInvoiceGenerationStartingAtOffset(TypedDict, total=False): - """ - The offset at which Metronome should start generating usage invoices, relative to the contract start date. If unspecified, contract start date will be used. This is useful to set if you want to import historical invoices via our 'Create Historical Invoices' API rather than having Metronome automatically generate them. - """ - - unit: Required[Literal["DAYS", "WEEKS", "MONTHS", "YEARS"]] - - value: Required[int] - - -class UsageStatementSchedule(TypedDict, total=False): - frequency: Required[Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"]] - - day: Literal["FIRST_OF_MONTH", "CONTRACT_START"] - """If not provided, defaults to the first day of the month.""" - - invoice_generation_starting_at_offset: UsageStatementScheduleInvoiceGenerationStartingAtOffset - """ - The offset at which Metronome should start generating usage invoices, relative - to the contract start date. If unspecified, contract start date will be used. - This is useful to set if you want to import historical invoices via our 'Create - Historical Invoices' API rather than having Metronome automatically generate - them. - """ diff --git a/src/metronome/types/v1/package_create_response.py b/src/metronome/types/v1/package_create_response.py deleted file mode 100644 index 5d8ed41c9..000000000 --- a/src/metronome/types/v1/package_create_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel -from ..shared.id import ID - -__all__ = ["PackageCreateResponse"] - - -class PackageCreateResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v1/package_list_contracts_on_package_params.py b/src/metronome/types/v1/package_list_contracts_on_package_params.py deleted file mode 100644 index 28a70833e..000000000 --- a/src/metronome/types/v1/package_list_contracts_on_package_params.py +++ /dev/null @@ -1,38 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ..._utils import PropertyInfo - -__all__ = ["PackageListContractsOnPackageParams"] - - -class PackageListContractsOnPackageParams(TypedDict, total=False): - package_id: Required[str] - - limit: int - """Max number of results that should be returned""" - - next_page: str - """Cursor that indicates where the next page of results should start.""" - - covering_date: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Optional RFC 3339 timestamp. - - Only include contracts active on the provided date. This cannot be provided if - starting_at filter is provided. - """ - - include_archived: bool - """Default false. Determines whether to include archived contracts in the results""" - - starting_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Optional RFC 3339 timestamp. - - Only include contracts that started on or after this date. This cannot be - provided if covering_date filter is provided. - """ diff --git a/src/metronome/types/v1/package_list_contracts_on_package_response.py b/src/metronome/types/v1/package_list_contracts_on_package_response.py deleted file mode 100644 index 5abd83c9c..000000000 --- a/src/metronome/types/v1/package_list_contracts_on_package_response.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional -from datetime import datetime - -from ..._models import BaseModel - -__all__ = ["PackageListContractsOnPackageResponse"] - - -class PackageListContractsOnPackageResponse(BaseModel): - contract_id: str - - customer_id: str - - starting_at: datetime - - archived_at: Optional[datetime] = None - - ending_before: Optional[datetime] = None diff --git a/src/metronome/types/v1/package_list_params.py b/src/metronome/types/v1/package_list_params.py deleted file mode 100644 index 258521286..000000000 --- a/src/metronome/types/v1/package_list_params.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, TypedDict - -__all__ = ["PackageListParams"] - - -class PackageListParams(TypedDict, total=False): - limit: int - """The maximum number of packages to return. Defaults to 10.""" - - next_page: str - """Cursor that indicates where the next page of results should start.""" - - archive_filter: Literal["ARCHIVED", "NOT_ARCHIVED", "ALL"] - """Filter packages by archived status. Defaults to NOT_ARCHIVED.""" diff --git a/src/metronome/types/v1/package_list_response.py b/src/metronome/types/v1/package_list_response.py deleted file mode 100644 index 7e1768eeb..000000000 --- a/src/metronome/types/v1/package_list_response.py +++ /dev/null @@ -1,807 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from datetime import datetime -from typing_extensions import Literal - -from ..._models import BaseModel -from ..shared.override_tier import OverrideTier -from ..shared.overwrite_rate import OverwriteRate -from ..shared.commit_specifier import CommitSpecifier -from ..shared.credit_type_data import CreditTypeData -from ..shared.spend_threshold_configuration import SpendThresholdConfiguration -from ..shared.prepaid_balance_threshold_configuration import PrepaidBalanceThresholdConfiguration - -__all__ = [ - "PackageListResponse", - "Commit", - "CommitProduct", - "CommitAccessSchedule", - "CommitAccessScheduleScheduleItem", - "CommitAccessScheduleScheduleItemDuration", - "CommitAccessScheduleScheduleItemStartingAtOffset", - "CommitInvoiceSchedule", - "CommitInvoiceScheduleScheduleItem", - "CommitInvoiceScheduleScheduleItemDateOffset", - "Override", - "OverrideOverrideSpecifier", - "OverrideStartingAtOffset", - "OverrideDuration", - "OverrideProduct", - "ScheduledCharge", - "ScheduledChargeProduct", - "ScheduledChargeSchedule", - "ScheduledChargeScheduleScheduleItem", - "ScheduledChargeScheduleScheduleItemDateOffset", - "UsageStatementSchedule", - "Alias", - "Credit", - "CreditProduct", - "CreditAccessSchedule", - "CreditAccessScheduleScheduleItem", - "CreditAccessScheduleScheduleItemDuration", - "CreditAccessScheduleScheduleItemStartingAtOffset", - "Duration", - "RecurringCommit", - "RecurringCommitAccessAmount", - "RecurringCommitCommitDuration", - "RecurringCommitProduct", - "RecurringCommitStartingAtOffset", - "RecurringCommitDuration", - "RecurringCommitInvoiceAmount", - "RecurringCommitSubscriptionConfig", - "RecurringCommitSubscriptionConfigApplySeatIncreaseConfig", - "RecurringCredit", - "RecurringCreditAccessAmount", - "RecurringCreditCommitDuration", - "RecurringCreditProduct", - "RecurringCreditStartingAtOffset", - "RecurringCreditDuration", - "RecurringCreditSubscriptionConfig", - "RecurringCreditSubscriptionConfigApplySeatIncreaseConfig", - "Subscription", - "SubscriptionProration", - "SubscriptionSubscriptionRate", - "SubscriptionSubscriptionRateProduct", - "SubscriptionDuration", - "SubscriptionSeatConfig", - "SubscriptionStartingAtOffset", -] - - -class CommitProduct(BaseModel): - id: str - - name: str - - -class CommitAccessScheduleScheduleItemDuration(BaseModel): - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class CommitAccessScheduleScheduleItemStartingAtOffset(BaseModel): - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class CommitAccessScheduleScheduleItem(BaseModel): - id: str - - amount: float - - duration: CommitAccessScheduleScheduleItemDuration - - starting_at_offset: CommitAccessScheduleScheduleItemStartingAtOffset - - -class CommitAccessSchedule(BaseModel): - """ - The schedule that the customer will gain access to the credits purposed with this commit. - """ - - credit_type: CreditTypeData - - schedule_items: List[CommitAccessScheduleScheduleItem] - - -class CommitInvoiceScheduleScheduleItemDateOffset(BaseModel): - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class CommitInvoiceScheduleScheduleItem(BaseModel): - id: str - - date_offset: CommitInvoiceScheduleScheduleItemDateOffset - - quantity: float - - unit_price: float - - -class CommitInvoiceSchedule(BaseModel): - """The schedule that the customer will be invoiced for this commit.""" - - credit_type: CreditTypeData - - do_not_invoice: bool - """If true, this schedule will not generate an invoice.""" - - schedule_items: List[CommitInvoiceScheduleScheduleItem] - - -class Commit(BaseModel): - id: str - - product: CommitProduct - - type: Literal["PREPAID", "POSTPAID"] - - access_schedule: Optional[CommitAccessSchedule] = None - """ - The schedule that the customer will gain access to the credits purposed with - this commit. - """ - - applicable_product_ids: Optional[List[str]] = None - - applicable_product_tags: Optional[List[str]] = None - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: Optional[str] = None - - invoice_schedule: Optional[CommitInvoiceSchedule] = None - """The schedule that the customer will be invoiced for this commit.""" - - name: Optional[str] = None - - priority: Optional[float] = None - """ - If multiple credits or commits are applicable, the one with the lower priority - will apply first. - """ - - rate_type: Optional[Literal["COMMIT_RATE", "LIST_RATE"]] = None - - rollover_fraction: Optional[float] = None - - specifiers: Optional[List[CommitSpecifier]] = None - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. - """ - - -class OverrideOverrideSpecifier(BaseModel): - billing_frequency: Optional[Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"]] = None - - commit_template_ids: Optional[List[str]] = None - - presentation_group_values: Optional[Dict[str, Optional[str]]] = None - - pricing_group_values: Optional[Dict[str, str]] = None - - product_id: Optional[str] = None - - product_tags: Optional[List[str]] = None - - recurring_commit_template_ids: Optional[List[str]] = None - - recurring_credit_template_ids: Optional[List[str]] = None - - -class OverrideStartingAtOffset(BaseModel): - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class OverrideDuration(BaseModel): - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class OverrideProduct(BaseModel): - id: str - - name: str - - -class Override(BaseModel): - id: str - - override_specifiers: List[OverrideOverrideSpecifier] - - starting_at_offset: OverrideStartingAtOffset - - applicable_product_tags: Optional[List[str]] = None - - duration: Optional[OverrideDuration] = None - - entitled: Optional[bool] = None - - is_commit_specific: Optional[bool] = None - - multiplier: Optional[float] = None - - override_tiers: Optional[List[OverrideTier]] = None - - overwrite_rate: Optional[OverwriteRate] = None - - priority: Optional[float] = None - - product: Optional[OverrideProduct] = None - - target: Optional[Literal["COMMIT_RATE", "LIST_RATE"]] = None - - type: Optional[Literal["OVERWRITE", "MULTIPLIER", "TIERED"]] = None - - -class ScheduledChargeProduct(BaseModel): - id: str - - name: str - - -class ScheduledChargeScheduleScheduleItemDateOffset(BaseModel): - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class ScheduledChargeScheduleScheduleItem(BaseModel): - id: str - - date_offset: ScheduledChargeScheduleScheduleItemDateOffset - - quantity: float - - unit_price: float - - -class ScheduledChargeSchedule(BaseModel): - credit_type: CreditTypeData - - schedule_items: List[ScheduledChargeScheduleScheduleItem] - - -class ScheduledCharge(BaseModel): - id: str - - product: ScheduledChargeProduct - - schedule: ScheduledChargeSchedule - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: Optional[str] = None - - name: Optional[str] = None - - -class UsageStatementSchedule(BaseModel): - frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"] - - -class Alias(BaseModel): - name: str - - ending_before: Optional[datetime] = None - - starting_at: Optional[datetime] = None - - -class CreditProduct(BaseModel): - id: str - - name: str - - -class CreditAccessScheduleScheduleItemDuration(BaseModel): - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class CreditAccessScheduleScheduleItemStartingAtOffset(BaseModel): - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class CreditAccessScheduleScheduleItem(BaseModel): - id: str - - amount: float - - duration: CreditAccessScheduleScheduleItemDuration - - starting_at_offset: CreditAccessScheduleScheduleItemStartingAtOffset - - -class CreditAccessSchedule(BaseModel): - credit_type: CreditTypeData - - schedule_items: List[CreditAccessScheduleScheduleItem] - - -class Credit(BaseModel): - id: str - - product: CreditProduct - - access_schedule: Optional[CreditAccessSchedule] = None - - applicable_product_ids: Optional[List[str]] = None - - applicable_product_tags: Optional[List[str]] = None - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: Optional[str] = None - - name: Optional[str] = None - - priority: Optional[float] = None - - rate_type: Optional[Literal["COMMIT_RATE", "LIST_RATE"]] = None - - specifiers: Optional[List[CommitSpecifier]] = None - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. - """ - - -class Duration(BaseModel): - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class RecurringCommitAccessAmount(BaseModel): - """The amount of commit to grant.""" - - credit_type_id: str - - unit_price: float - - quantity: Optional[float] = None - - -class RecurringCommitCommitDuration(BaseModel): - """The amount of time each of the created commits will be valid for""" - - value: float - - unit: Optional[Literal["PERIODS"]] = None - - -class RecurringCommitProduct(BaseModel): - id: str - - name: str - - -class RecurringCommitStartingAtOffset(BaseModel): - """ - Offset relative to the contract start date that determines the start time for the first commit - """ - - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class RecurringCommitDuration(BaseModel): - """ - Offset relative to the recurring credit start that determines when the contract will stop creating recurring commits. optional - """ - - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class RecurringCommitInvoiceAmount(BaseModel): - """The amount the customer should be billed for the commit.""" - - credit_type_id: str - - quantity: float - - unit_price: float - - -class RecurringCommitSubscriptionConfigApplySeatIncreaseConfig(BaseModel): - is_prorated: bool - """Indicates whether a mid-period seat increase should be prorated.""" - - -class RecurringCommitSubscriptionConfig(BaseModel): - """Attach a subscription to the recurring commit/credit.""" - - allocation: Literal["INDIVIDUAL", "POOLED"] - - apply_seat_increase_config: RecurringCommitSubscriptionConfigApplySeatIncreaseConfig - - subscription_template_id: str - - -class RecurringCommit(BaseModel): - id: str - - access_amount: RecurringCommitAccessAmount - """The amount of commit to grant.""" - - commit_duration: RecurringCommitCommitDuration - """The amount of time each of the created commits will be valid for""" - - priority: float - - product: RecurringCommitProduct - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - """Whether the created commits will use the commit rate or list rate""" - - starting_at_offset: RecurringCommitStartingAtOffset - """ - Offset relative to the contract start date that determines the start time for - the first commit - """ - - applicable_product_ids: Optional[List[str]] = None - """Will be passed down to the individual commits""" - - applicable_product_tags: Optional[List[str]] = None - """Will be passed down to the individual commits""" - - description: Optional[str] = None - - duration: Optional[RecurringCommitDuration] = None - """ - Offset relative to the recurring credit start that determines when the contract - will stop creating recurring commits. optional - """ - - invoice_amount: Optional[RecurringCommitInvoiceAmount] = None - """The amount the customer should be billed for the commit.""" - - name: Optional[str] = None - - proration: Optional[Literal["NONE", "FIRST", "LAST", "FIRST_AND_LAST"]] = None - """Determines whether the first and last commit will be prorated. - - If not provided, the default is FIRST_AND_LAST (i.e. prorate both the first and - last commits). - """ - - recurrence_frequency: Optional[Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"]] = None - """The frequency at which the recurring commits will be created. - - If not provided: - The commits will be created on the usage invoice frequency. - If provided: - The period defined in the duration will correspond to this - frequency. - Commits will be created aligned with the recurring commit's - starting_at rather than the usage invoice dates. - """ - - rollover_fraction: Optional[float] = None - """Will be passed down to the individual commits. - - This controls how much of an individual unexpired commit will roll over upon - contract transition. Must be between 0 and 1. - """ - - specifiers: Optional[List[CommitSpecifier]] = None - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. - """ - - subscription_config: Optional[RecurringCommitSubscriptionConfig] = None - """Attach a subscription to the recurring commit/credit.""" - - -class RecurringCreditAccessAmount(BaseModel): - """The amount of commit to grant.""" - - credit_type_id: str - - unit_price: float - - quantity: Optional[float] = None - - -class RecurringCreditCommitDuration(BaseModel): - """The amount of time each of the created commits will be valid for""" - - value: float - - unit: Optional[Literal["PERIODS"]] = None - - -class RecurringCreditProduct(BaseModel): - id: str - - name: str - - -class RecurringCreditStartingAtOffset(BaseModel): - """ - Offset relative to the contract start date that determines the start time for the first commit - """ - - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class RecurringCreditDuration(BaseModel): - """ - Offset relative to the recurring credit start that determines when the contract will stop creating recurring commits. optional - """ - - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class RecurringCreditSubscriptionConfigApplySeatIncreaseConfig(BaseModel): - is_prorated: bool - """Indicates whether a mid-period seat increase should be prorated.""" - - -class RecurringCreditSubscriptionConfig(BaseModel): - """Attach a subscription to the recurring commit/credit.""" - - allocation: Literal["INDIVIDUAL", "POOLED"] - - apply_seat_increase_config: RecurringCreditSubscriptionConfigApplySeatIncreaseConfig - - subscription_template_id: str - - -class RecurringCredit(BaseModel): - id: str - - access_amount: RecurringCreditAccessAmount - """The amount of commit to grant.""" - - commit_duration: RecurringCreditCommitDuration - """The amount of time each of the created commits will be valid for""" - - priority: float - - product: RecurringCreditProduct - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - """Whether the created commits will use the commit rate or list rate""" - - starting_at_offset: RecurringCreditStartingAtOffset - """ - Offset relative to the contract start date that determines the start time for - the first commit - """ - - applicable_product_ids: Optional[List[str]] = None - """Will be passed down to the individual commits""" - - applicable_product_tags: Optional[List[str]] = None - """Will be passed down to the individual commits""" - - description: Optional[str] = None - - duration: Optional[RecurringCreditDuration] = None - """ - Offset relative to the recurring credit start that determines when the contract - will stop creating recurring commits. optional - """ - - name: Optional[str] = None - - proration: Optional[Literal["NONE", "FIRST", "LAST", "FIRST_AND_LAST"]] = None - """Determines whether the first and last commit will be prorated. - - If not provided, the default is FIRST_AND_LAST (i.e. prorate both the first and - last commits). - """ - - recurrence_frequency: Optional[Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"]] = None - """The frequency at which the recurring commits will be created. - - If not provided: - The commits will be created on the usage invoice frequency. - If provided: - The period defined in the duration will correspond to this - frequency. - Commits will be created aligned with the recurring commit's - starting_at rather than the usage invoice dates. - """ - - rollover_fraction: Optional[float] = None - """Will be passed down to the individual commits. - - This controls how much of an individual unexpired commit will roll over upon - contract transition. Must be between 0 and 1. - """ - - specifiers: Optional[List[CommitSpecifier]] = None - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. - """ - - subscription_config: Optional[RecurringCreditSubscriptionConfig] = None - """Attach a subscription to the recurring commit/credit.""" - - -class SubscriptionProration(BaseModel): - invoice_behavior: Literal["BILL_IMMEDIATELY", "BILL_ON_NEXT_COLLECTION_DATE"] - - is_prorated: bool - - -class SubscriptionSubscriptionRateProduct(BaseModel): - id: str - - name: str - - -class SubscriptionSubscriptionRate(BaseModel): - billing_frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"] - - product: SubscriptionSubscriptionRateProduct - - -class SubscriptionDuration(BaseModel): - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class SubscriptionSeatConfig(BaseModel): - seat_group_key: str - """ - The property name, sent on usage events, that identifies the seat ID associated - with the usage event. For example, the property name might be seat_id or - user_id. The property must be set as a group key on billable metrics and a - presentation/pricing group key on contract products. This allows linked - recurring credits with an allocation per seat to be consumed by only one seat's - usage. - """ - - -class SubscriptionStartingAtOffset(BaseModel): - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class Subscription(BaseModel): - collection_schedule: Literal["ADVANCE", "ARREARS"] - - proration: SubscriptionProration - - subscription_rate: SubscriptionSubscriptionRate - - id: Optional[str] = None - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: Optional[str] = None - - duration: Optional[SubscriptionDuration] = None - - fiat_credit_type_id: Optional[str] = None - - initial_quantity: Optional[float] = None - - name: Optional[str] = None - - quantity_management_mode: Optional[Literal["SEAT_BASED", "QUANTITY_ONLY"]] = None - """Determines how the subscription's quantity is controlled. - - Defaults to QUANTITY_ONLY. **QUANTITY_ONLY**: The subscription quantity is - specified directly on the subscription. `initial_quantity` must be provided with - this option. Compatible with recurring commits/credits that use POOLED - allocation. **SEAT_BASED**: Use when you want to pass specific seat identifiers - (e.g. add user_123) to increment and decrement a subscription quantity, rather - than directly providing the quantity. You must use a SEAT_BASED subscription to - use a linked recurring credit with an allocation per seat. `seat_config` must be - provided with this option. - """ - - seat_config: Optional[SubscriptionSeatConfig] = None - - starting_at_offset: Optional[SubscriptionStartingAtOffset] = None - - -class PackageListResponse(BaseModel): - id: str - - commits: List[Commit] - - created_at: datetime - - created_by: str - - overrides: List[Override] - - scheduled_charges: List[ScheduledCharge] - - usage_statement_schedule: UsageStatementSchedule - - aliases: Optional[List[Alias]] = None - - archived_at: Optional[datetime] = None - - billing_provider: Optional[ - Literal[ - "aws_marketplace", - "stripe", - "netsuite", - "custom", - "azure_marketplace", - "quickbooks_online", - "workday", - "gcp_marketplace", - "metronome", - ] - ] = None - - credits: Optional[List[Credit]] = None - - delivery_method: Optional[Literal["direct_to_billing_provider", "aws_sqs", "tackle", "aws_sns"]] = None - - duration: Optional[Duration] = None - - multiplier_override_prioritization: Optional[Literal["LOWEST_MULTIPLIER", "EXPLICIT"]] = None - """ - Defaults to LOWEST_MULTIPLIER, which applies the greatest discount to list - prices automatically. EXPLICIT prioritization requires specifying priorities for - each multiplier; the one with the lowest priority value will be prioritized - first. - """ - - name: Optional[str] = None - - net_payment_terms_days: Optional[float] = None - - prepaid_balance_threshold_configuration: Optional[PrepaidBalanceThresholdConfiguration] = None - - rate_card_id: Optional[str] = None - - recurring_commits: Optional[List[RecurringCommit]] = None - - recurring_credits: Optional[List[RecurringCredit]] = None - - scheduled_charges_on_usage_invoices: Optional[Literal["ALL"]] = None - """ - Determines which scheduled and commit charges to consolidate onto the Contract's - usage invoice. The charge's `timestamp` must match the usage invoice's - `ending_before` date for consolidation to occur. This field cannot be modified - after a Contract has been created. If this field is omitted, charges will appear - on a separate invoice from usage charges. - """ - - spend_threshold_configuration: Optional[SpendThresholdConfiguration] = None - - subscriptions: Optional[List[Subscription]] = None - - uniqueness_key: Optional[str] = None - """Prevents the creation of duplicates. - - If a request to create a record is made with a previously used uniqueness key, a - new record will not be created and the request will fail with a 409 error. - """ diff --git a/src/metronome/types/v1/package_retrieve_params.py b/src/metronome/types/v1/package_retrieve_params.py deleted file mode 100644 index e869f6dc1..000000000 --- a/src/metronome/types/v1/package_retrieve_params.py +++ /dev/null @@ -1,11 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["PackageRetrieveParams"] - - -class PackageRetrieveParams(TypedDict, total=False): - package_id: Required[str] diff --git a/src/metronome/types/v1/package_retrieve_response.py b/src/metronome/types/v1/package_retrieve_response.py deleted file mode 100644 index 44c4662bd..000000000 --- a/src/metronome/types/v1/package_retrieve_response.py +++ /dev/null @@ -1,812 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from datetime import datetime -from typing_extensions import Literal - -from ..._models import BaseModel -from ..shared.override_tier import OverrideTier -from ..shared.overwrite_rate import OverwriteRate -from ..shared.commit_specifier import CommitSpecifier -from ..shared.credit_type_data import CreditTypeData -from ..shared.spend_threshold_configuration import SpendThresholdConfiguration -from ..shared.prepaid_balance_threshold_configuration import PrepaidBalanceThresholdConfiguration - -__all__ = [ - "PackageRetrieveResponse", - "Data", - "DataCommit", - "DataCommitProduct", - "DataCommitAccessSchedule", - "DataCommitAccessScheduleScheduleItem", - "DataCommitAccessScheduleScheduleItemDuration", - "DataCommitAccessScheduleScheduleItemStartingAtOffset", - "DataCommitInvoiceSchedule", - "DataCommitInvoiceScheduleScheduleItem", - "DataCommitInvoiceScheduleScheduleItemDateOffset", - "DataOverride", - "DataOverrideOverrideSpecifier", - "DataOverrideStartingAtOffset", - "DataOverrideDuration", - "DataOverrideProduct", - "DataScheduledCharge", - "DataScheduledChargeProduct", - "DataScheduledChargeSchedule", - "DataScheduledChargeScheduleScheduleItem", - "DataScheduledChargeScheduleScheduleItemDateOffset", - "DataUsageStatementSchedule", - "DataAlias", - "DataCredit", - "DataCreditProduct", - "DataCreditAccessSchedule", - "DataCreditAccessScheduleScheduleItem", - "DataCreditAccessScheduleScheduleItemDuration", - "DataCreditAccessScheduleScheduleItemStartingAtOffset", - "DataDuration", - "DataRecurringCommit", - "DataRecurringCommitAccessAmount", - "DataRecurringCommitCommitDuration", - "DataRecurringCommitProduct", - "DataRecurringCommitStartingAtOffset", - "DataRecurringCommitDuration", - "DataRecurringCommitInvoiceAmount", - "DataRecurringCommitSubscriptionConfig", - "DataRecurringCommitSubscriptionConfigApplySeatIncreaseConfig", - "DataRecurringCredit", - "DataRecurringCreditAccessAmount", - "DataRecurringCreditCommitDuration", - "DataRecurringCreditProduct", - "DataRecurringCreditStartingAtOffset", - "DataRecurringCreditDuration", - "DataRecurringCreditSubscriptionConfig", - "DataRecurringCreditSubscriptionConfigApplySeatIncreaseConfig", - "DataSubscription", - "DataSubscriptionProration", - "DataSubscriptionSubscriptionRate", - "DataSubscriptionSubscriptionRateProduct", - "DataSubscriptionDuration", - "DataSubscriptionSeatConfig", - "DataSubscriptionStartingAtOffset", -] - - -class DataCommitProduct(BaseModel): - id: str - - name: str - - -class DataCommitAccessScheduleScheduleItemDuration(BaseModel): - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class DataCommitAccessScheduleScheduleItemStartingAtOffset(BaseModel): - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class DataCommitAccessScheduleScheduleItem(BaseModel): - id: str - - amount: float - - duration: DataCommitAccessScheduleScheduleItemDuration - - starting_at_offset: DataCommitAccessScheduleScheduleItemStartingAtOffset - - -class DataCommitAccessSchedule(BaseModel): - """ - The schedule that the customer will gain access to the credits purposed with this commit. - """ - - credit_type: CreditTypeData - - schedule_items: List[DataCommitAccessScheduleScheduleItem] - - -class DataCommitInvoiceScheduleScheduleItemDateOffset(BaseModel): - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class DataCommitInvoiceScheduleScheduleItem(BaseModel): - id: str - - date_offset: DataCommitInvoiceScheduleScheduleItemDateOffset - - quantity: float - - unit_price: float - - -class DataCommitInvoiceSchedule(BaseModel): - """The schedule that the customer will be invoiced for this commit.""" - - credit_type: CreditTypeData - - do_not_invoice: bool - """If true, this schedule will not generate an invoice.""" - - schedule_items: List[DataCommitInvoiceScheduleScheduleItem] - - -class DataCommit(BaseModel): - id: str - - product: DataCommitProduct - - type: Literal["PREPAID", "POSTPAID"] - - access_schedule: Optional[DataCommitAccessSchedule] = None - """ - The schedule that the customer will gain access to the credits purposed with - this commit. - """ - - applicable_product_ids: Optional[List[str]] = None - - applicable_product_tags: Optional[List[str]] = None - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: Optional[str] = None - - invoice_schedule: Optional[DataCommitInvoiceSchedule] = None - """The schedule that the customer will be invoiced for this commit.""" - - name: Optional[str] = None - - priority: Optional[float] = None - """ - If multiple credits or commits are applicable, the one with the lower priority - will apply first. - """ - - rate_type: Optional[Literal["COMMIT_RATE", "LIST_RATE"]] = None - - rollover_fraction: Optional[float] = None - - specifiers: Optional[List[CommitSpecifier]] = None - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. - """ - - -class DataOverrideOverrideSpecifier(BaseModel): - billing_frequency: Optional[Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"]] = None - - commit_template_ids: Optional[List[str]] = None - - presentation_group_values: Optional[Dict[str, Optional[str]]] = None - - pricing_group_values: Optional[Dict[str, str]] = None - - product_id: Optional[str] = None - - product_tags: Optional[List[str]] = None - - recurring_commit_template_ids: Optional[List[str]] = None - - recurring_credit_template_ids: Optional[List[str]] = None - - -class DataOverrideStartingAtOffset(BaseModel): - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class DataOverrideDuration(BaseModel): - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class DataOverrideProduct(BaseModel): - id: str - - name: str - - -class DataOverride(BaseModel): - id: str - - override_specifiers: List[DataOverrideOverrideSpecifier] - - starting_at_offset: DataOverrideStartingAtOffset - - applicable_product_tags: Optional[List[str]] = None - - duration: Optional[DataOverrideDuration] = None - - entitled: Optional[bool] = None - - is_commit_specific: Optional[bool] = None - - multiplier: Optional[float] = None - - override_tiers: Optional[List[OverrideTier]] = None - - overwrite_rate: Optional[OverwriteRate] = None - - priority: Optional[float] = None - - product: Optional[DataOverrideProduct] = None - - target: Optional[Literal["COMMIT_RATE", "LIST_RATE"]] = None - - type: Optional[Literal["OVERWRITE", "MULTIPLIER", "TIERED"]] = None - - -class DataScheduledChargeProduct(BaseModel): - id: str - - name: str - - -class DataScheduledChargeScheduleScheduleItemDateOffset(BaseModel): - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class DataScheduledChargeScheduleScheduleItem(BaseModel): - id: str - - date_offset: DataScheduledChargeScheduleScheduleItemDateOffset - - quantity: float - - unit_price: float - - -class DataScheduledChargeSchedule(BaseModel): - credit_type: CreditTypeData - - schedule_items: List[DataScheduledChargeScheduleScheduleItem] - - -class DataScheduledCharge(BaseModel): - id: str - - product: DataScheduledChargeProduct - - schedule: DataScheduledChargeSchedule - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: Optional[str] = None - - name: Optional[str] = None - - -class DataUsageStatementSchedule(BaseModel): - frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"] - - -class DataAlias(BaseModel): - name: str - - ending_before: Optional[datetime] = None - - starting_at: Optional[datetime] = None - - -class DataCreditProduct(BaseModel): - id: str - - name: str - - -class DataCreditAccessScheduleScheduleItemDuration(BaseModel): - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class DataCreditAccessScheduleScheduleItemStartingAtOffset(BaseModel): - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class DataCreditAccessScheduleScheduleItem(BaseModel): - id: str - - amount: float - - duration: DataCreditAccessScheduleScheduleItemDuration - - starting_at_offset: DataCreditAccessScheduleScheduleItemStartingAtOffset - - -class DataCreditAccessSchedule(BaseModel): - credit_type: CreditTypeData - - schedule_items: List[DataCreditAccessScheduleScheduleItem] - - -class DataCredit(BaseModel): - id: str - - product: DataCreditProduct - - access_schedule: Optional[DataCreditAccessSchedule] = None - - applicable_product_ids: Optional[List[str]] = None - - applicable_product_tags: Optional[List[str]] = None - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: Optional[str] = None - - name: Optional[str] = None - - priority: Optional[float] = None - - rate_type: Optional[Literal["COMMIT_RATE", "LIST_RATE"]] = None - - specifiers: Optional[List[CommitSpecifier]] = None - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. - """ - - -class DataDuration(BaseModel): - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class DataRecurringCommitAccessAmount(BaseModel): - """The amount of commit to grant.""" - - credit_type_id: str - - unit_price: float - - quantity: Optional[float] = None - - -class DataRecurringCommitCommitDuration(BaseModel): - """The amount of time each of the created commits will be valid for""" - - value: float - - unit: Optional[Literal["PERIODS"]] = None - - -class DataRecurringCommitProduct(BaseModel): - id: str - - name: str - - -class DataRecurringCommitStartingAtOffset(BaseModel): - """ - Offset relative to the contract start date that determines the start time for the first commit - """ - - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class DataRecurringCommitDuration(BaseModel): - """ - Offset relative to the recurring credit start that determines when the contract will stop creating recurring commits. optional - """ - - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class DataRecurringCommitInvoiceAmount(BaseModel): - """The amount the customer should be billed for the commit.""" - - credit_type_id: str - - quantity: float - - unit_price: float - - -class DataRecurringCommitSubscriptionConfigApplySeatIncreaseConfig(BaseModel): - is_prorated: bool - """Indicates whether a mid-period seat increase should be prorated.""" - - -class DataRecurringCommitSubscriptionConfig(BaseModel): - """Attach a subscription to the recurring commit/credit.""" - - allocation: Literal["INDIVIDUAL", "POOLED"] - - apply_seat_increase_config: DataRecurringCommitSubscriptionConfigApplySeatIncreaseConfig - - subscription_template_id: str - - -class DataRecurringCommit(BaseModel): - id: str - - access_amount: DataRecurringCommitAccessAmount - """The amount of commit to grant.""" - - commit_duration: DataRecurringCommitCommitDuration - """The amount of time each of the created commits will be valid for""" - - priority: float - - product: DataRecurringCommitProduct - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - """Whether the created commits will use the commit rate or list rate""" - - starting_at_offset: DataRecurringCommitStartingAtOffset - """ - Offset relative to the contract start date that determines the start time for - the first commit - """ - - applicable_product_ids: Optional[List[str]] = None - """Will be passed down to the individual commits""" - - applicable_product_tags: Optional[List[str]] = None - """Will be passed down to the individual commits""" - - description: Optional[str] = None - - duration: Optional[DataRecurringCommitDuration] = None - """ - Offset relative to the recurring credit start that determines when the contract - will stop creating recurring commits. optional - """ - - invoice_amount: Optional[DataRecurringCommitInvoiceAmount] = None - """The amount the customer should be billed for the commit.""" - - name: Optional[str] = None - - proration: Optional[Literal["NONE", "FIRST", "LAST", "FIRST_AND_LAST"]] = None - """Determines whether the first and last commit will be prorated. - - If not provided, the default is FIRST_AND_LAST (i.e. prorate both the first and - last commits). - """ - - recurrence_frequency: Optional[Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"]] = None - """The frequency at which the recurring commits will be created. - - If not provided: - The commits will be created on the usage invoice frequency. - If provided: - The period defined in the duration will correspond to this - frequency. - Commits will be created aligned with the recurring commit's - starting_at rather than the usage invoice dates. - """ - - rollover_fraction: Optional[float] = None - """Will be passed down to the individual commits. - - This controls how much of an individual unexpired commit will roll over upon - contract transition. Must be between 0 and 1. - """ - - specifiers: Optional[List[CommitSpecifier]] = None - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. - """ - - subscription_config: Optional[DataRecurringCommitSubscriptionConfig] = None - """Attach a subscription to the recurring commit/credit.""" - - -class DataRecurringCreditAccessAmount(BaseModel): - """The amount of commit to grant.""" - - credit_type_id: str - - unit_price: float - - quantity: Optional[float] = None - - -class DataRecurringCreditCommitDuration(BaseModel): - """The amount of time each of the created commits will be valid for""" - - value: float - - unit: Optional[Literal["PERIODS"]] = None - - -class DataRecurringCreditProduct(BaseModel): - id: str - - name: str - - -class DataRecurringCreditStartingAtOffset(BaseModel): - """ - Offset relative to the contract start date that determines the start time for the first commit - """ - - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class DataRecurringCreditDuration(BaseModel): - """ - Offset relative to the recurring credit start that determines when the contract will stop creating recurring commits. optional - """ - - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class DataRecurringCreditSubscriptionConfigApplySeatIncreaseConfig(BaseModel): - is_prorated: bool - """Indicates whether a mid-period seat increase should be prorated.""" - - -class DataRecurringCreditSubscriptionConfig(BaseModel): - """Attach a subscription to the recurring commit/credit.""" - - allocation: Literal["INDIVIDUAL", "POOLED"] - - apply_seat_increase_config: DataRecurringCreditSubscriptionConfigApplySeatIncreaseConfig - - subscription_template_id: str - - -class DataRecurringCredit(BaseModel): - id: str - - access_amount: DataRecurringCreditAccessAmount - """The amount of commit to grant.""" - - commit_duration: DataRecurringCreditCommitDuration - """The amount of time each of the created commits will be valid for""" - - priority: float - - product: DataRecurringCreditProduct - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - """Whether the created commits will use the commit rate or list rate""" - - starting_at_offset: DataRecurringCreditStartingAtOffset - """ - Offset relative to the contract start date that determines the start time for - the first commit - """ - - applicable_product_ids: Optional[List[str]] = None - """Will be passed down to the individual commits""" - - applicable_product_tags: Optional[List[str]] = None - """Will be passed down to the individual commits""" - - description: Optional[str] = None - - duration: Optional[DataRecurringCreditDuration] = None - """ - Offset relative to the recurring credit start that determines when the contract - will stop creating recurring commits. optional - """ - - name: Optional[str] = None - - proration: Optional[Literal["NONE", "FIRST", "LAST", "FIRST_AND_LAST"]] = None - """Determines whether the first and last commit will be prorated. - - If not provided, the default is FIRST_AND_LAST (i.e. prorate both the first and - last commits). - """ - - recurrence_frequency: Optional[Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"]] = None - """The frequency at which the recurring commits will be created. - - If not provided: - The commits will be created on the usage invoice frequency. - If provided: - The period defined in the duration will correspond to this - frequency. - Commits will be created aligned with the recurring commit's - starting_at rather than the usage invoice dates. - """ - - rollover_fraction: Optional[float] = None - """Will be passed down to the individual commits. - - This controls how much of an individual unexpired commit will roll over upon - contract transition. Must be between 0 and 1. - """ - - specifiers: Optional[List[CommitSpecifier]] = None - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. - """ - - subscription_config: Optional[DataRecurringCreditSubscriptionConfig] = None - """Attach a subscription to the recurring commit/credit.""" - - -class DataSubscriptionProration(BaseModel): - invoice_behavior: Literal["BILL_IMMEDIATELY", "BILL_ON_NEXT_COLLECTION_DATE"] - - is_prorated: bool - - -class DataSubscriptionSubscriptionRateProduct(BaseModel): - id: str - - name: str - - -class DataSubscriptionSubscriptionRate(BaseModel): - billing_frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"] - - product: DataSubscriptionSubscriptionRateProduct - - -class DataSubscriptionDuration(BaseModel): - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class DataSubscriptionSeatConfig(BaseModel): - seat_group_key: str - """ - The property name, sent on usage events, that identifies the seat ID associated - with the usage event. For example, the property name might be seat_id or - user_id. The property must be set as a group key on billable metrics and a - presentation/pricing group key on contract products. This allows linked - recurring credits with an allocation per seat to be consumed by only one seat's - usage. - """ - - -class DataSubscriptionStartingAtOffset(BaseModel): - unit: Literal["DAYS", "WEEKS", "MONTHS", "YEARS"] - - value: int - - -class DataSubscription(BaseModel): - collection_schedule: Literal["ADVANCE", "ARREARS"] - - proration: DataSubscriptionProration - - subscription_rate: DataSubscriptionSubscriptionRate - - id: Optional[str] = None - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: Optional[str] = None - - duration: Optional[DataSubscriptionDuration] = None - - fiat_credit_type_id: Optional[str] = None - - initial_quantity: Optional[float] = None - - name: Optional[str] = None - - quantity_management_mode: Optional[Literal["SEAT_BASED", "QUANTITY_ONLY"]] = None - """Determines how the subscription's quantity is controlled. - - Defaults to QUANTITY_ONLY. **QUANTITY_ONLY**: The subscription quantity is - specified directly on the subscription. `initial_quantity` must be provided with - this option. Compatible with recurring commits/credits that use POOLED - allocation. **SEAT_BASED**: Use when you want to pass specific seat identifiers - (e.g. add user_123) to increment and decrement a subscription quantity, rather - than directly providing the quantity. You must use a SEAT_BASED subscription to - use a linked recurring credit with an allocation per seat. `seat_config` must be - provided with this option. - """ - - seat_config: Optional[DataSubscriptionSeatConfig] = None - - starting_at_offset: Optional[DataSubscriptionStartingAtOffset] = None - - -class Data(BaseModel): - id: str - - commits: List[DataCommit] - - created_at: datetime - - created_by: str - - overrides: List[DataOverride] - - scheduled_charges: List[DataScheduledCharge] - - usage_statement_schedule: DataUsageStatementSchedule - - aliases: Optional[List[DataAlias]] = None - - archived_at: Optional[datetime] = None - - billing_provider: Optional[ - Literal[ - "aws_marketplace", - "stripe", - "netsuite", - "custom", - "azure_marketplace", - "quickbooks_online", - "workday", - "gcp_marketplace", - "metronome", - ] - ] = None - - credits: Optional[List[DataCredit]] = None - - delivery_method: Optional[Literal["direct_to_billing_provider", "aws_sqs", "tackle", "aws_sns"]] = None - - duration: Optional[DataDuration] = None - - multiplier_override_prioritization: Optional[Literal["LOWEST_MULTIPLIER", "EXPLICIT"]] = None - """ - Defaults to LOWEST_MULTIPLIER, which applies the greatest discount to list - prices automatically. EXPLICIT prioritization requires specifying priorities for - each multiplier; the one with the lowest priority value will be prioritized - first. - """ - - name: Optional[str] = None - - net_payment_terms_days: Optional[float] = None - - prepaid_balance_threshold_configuration: Optional[PrepaidBalanceThresholdConfiguration] = None - - rate_card_id: Optional[str] = None - - recurring_commits: Optional[List[DataRecurringCommit]] = None - - recurring_credits: Optional[List[DataRecurringCredit]] = None - - scheduled_charges_on_usage_invoices: Optional[Literal["ALL"]] = None - """ - Determines which scheduled and commit charges to consolidate onto the Contract's - usage invoice. The charge's `timestamp` must match the usage invoice's - `ending_before` date for consolidation to occur. This field cannot be modified - after a Contract has been created. If this field is omitted, charges will appear - on a separate invoice from usage charges. - """ - - spend_threshold_configuration: Optional[SpendThresholdConfiguration] = None - - subscriptions: Optional[List[DataSubscription]] = None - - uniqueness_key: Optional[str] = None - """Prevents the creation of duplicates. - - If a request to create a record is made with a previously used uniqueness key, a - new record will not be created and the request will fail with a 409 error. - """ - - -class PackageRetrieveResponse(BaseModel): - data: Data diff --git a/src/metronome/types/v1/payment.py b/src/metronome/types/v1/payment.py deleted file mode 100644 index ce3aab66a..000000000 --- a/src/metronome/types/v1/payment.py +++ /dev/null @@ -1,72 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List, Optional -from datetime import datetime -from typing_extensions import Literal - -from ..._models import BaseModel -from .payment_status import PaymentStatus -from ..shared.credit_type_data import CreditTypeData - -__all__ = ["Payment", "PaymentGateway", "PaymentGatewayStripe", "PaymentGatewayStripeError", "RevenueSystemPayment"] - - -class PaymentGatewayStripeError(BaseModel): - code: Optional[str] = None - - decline_code: Optional[str] = None - - type: Optional[str] = None - - -class PaymentGatewayStripe(BaseModel): - payment_intent_id: str - - error: Optional[PaymentGatewayStripeError] = None - - payment_method_id: Optional[str] = None - - -class PaymentGateway(BaseModel): - stripe: PaymentGatewayStripe - - type: Literal["stripe"] - - -class RevenueSystemPayment(BaseModel): - revenue_system_provider: str - - sync_status: str - - error_message: Optional[str] = None - """The error message from the revenue system, if available.""" - - revenue_system_external_payment_id: Optional[str] = None - - -class Payment(BaseModel): - id: str - - amount: Optional[float] = None - - amount_paid: Optional[float] = None - - contract_id: Optional[str] = None - - created_at: Optional[datetime] = None - - customer_id: Optional[str] = None - - error_message: Optional[str] = None - - fiat_credit_type: Optional[CreditTypeData] = None - - invoice_id: Optional[str] = None - - payment_gateway: Optional[PaymentGateway] = None - - revenue_system_payments: Optional[List[RevenueSystemPayment]] = None - - status: Optional[PaymentStatus] = None - - updated_at: Optional[datetime] = None diff --git a/src/metronome/types/v1/payment_attempt_params.py b/src/metronome/types/v1/payment_attempt_params.py deleted file mode 100644 index 1579e3a16..000000000 --- a/src/metronome/types/v1/payment_attempt_params.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["PaymentAttemptParams"] - - -class PaymentAttemptParams(TypedDict, total=False): - customer_id: Required[str] - - invoice_id: Required[str] diff --git a/src/metronome/types/v1/payment_attempt_response.py b/src/metronome/types/v1/payment_attempt_response.py deleted file mode 100644 index 52c45c158..000000000 --- a/src/metronome/types/v1/payment_attempt_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .payment import Payment -from ..._models import BaseModel - -__all__ = ["PaymentAttemptResponse"] - - -class PaymentAttemptResponse(BaseModel): - data: Payment diff --git a/src/metronome/types/v1/payment_cancel_params.py b/src/metronome/types/v1/payment_cancel_params.py deleted file mode 100644 index b3666f14d..000000000 --- a/src/metronome/types/v1/payment_cancel_params.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["PaymentCancelParams"] - - -class PaymentCancelParams(TypedDict, total=False): - customer_id: Required[str] - - invoice_id: Required[str] diff --git a/src/metronome/types/v1/payment_cancel_response.py b/src/metronome/types/v1/payment_cancel_response.py deleted file mode 100644 index 12305d77b..000000000 --- a/src/metronome/types/v1/payment_cancel_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from .payment import Payment -from ..._models import BaseModel - -__all__ = ["PaymentCancelResponse"] - - -class PaymentCancelResponse(BaseModel): - data: Payment diff --git a/src/metronome/types/v1/payment_list_params.py b/src/metronome/types/v1/payment_list_params.py deleted file mode 100644 index e9a9fe8ea..000000000 --- a/src/metronome/types/v1/payment_list_params.py +++ /dev/null @@ -1,24 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import List -from typing_extensions import Required, TypedDict - -from .payment_status import PaymentStatus - -__all__ = ["PaymentListParams"] - - -class PaymentListParams(TypedDict, total=False): - customer_id: Required[str] - - invoice_id: Required[str] - - limit: int - """The maximum number of payments to return. Defaults to 25.""" - - next_page: str - """The next page token from a previous response.""" - - statuses: List[PaymentStatus] diff --git a/src/metronome/types/v1/payment_status.py b/src/metronome/types/v1/payment_status.py deleted file mode 100644 index f348de544..000000000 --- a/src/metronome/types/v1/payment_status.py +++ /dev/null @@ -1,7 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing_extensions import Literal, TypeAlias - -__all__ = ["PaymentStatus"] - -PaymentStatus: TypeAlias = Literal["pending", "requires_intervention", "paid", "canceled"] diff --git a/src/metronome/types/v1/plan_detail.py b/src/metronome/types/v1/plan_detail.py deleted file mode 100644 index 72123e951..000000000 --- a/src/metronome/types/v1/plan_detail.py +++ /dev/null @@ -1,77 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional - -from ..._models import BaseModel -from ..shared.credit_type_data import CreditTypeData - -__all__ = ["PlanDetail", "CreditGrant", "Minimum", "OverageRate"] - - -class CreditGrant(BaseModel): - amount_granted: float - - amount_granted_credit_type: CreditTypeData - - amount_paid: float - - amount_paid_credit_type: CreditTypeData - - effective_duration: float - - name: str - - priority: str - - send_invoice: bool - - reason: Optional[str] = None - - recurrence_duration: Optional[float] = None - - recurrence_interval: Optional[float] = None - - -class Minimum(BaseModel): - credit_type: CreditTypeData - - name: str - - start_period: float - """Used in price ramps. - - Indicates how many billing periods pass before the charge applies. - """ - - value: float - - -class OverageRate(BaseModel): - credit_type: CreditTypeData - - fiat_credit_type: CreditTypeData - - start_period: float - """Used in price ramps. - - Indicates how many billing periods pass before the charge applies. - """ - - to_fiat_conversion_factor: float - - -class PlanDetail(BaseModel): - id: str - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - name: str - - credit_grants: Optional[List[CreditGrant]] = None - - description: Optional[str] = None - - minimums: Optional[List[Minimum]] = None - - overage_rates: Optional[List[OverageRate]] = None diff --git a/src/metronome/types/v1/plan_get_details_response.py b/src/metronome/types/v1/plan_get_details_response.py deleted file mode 100644 index 4da291a85..000000000 --- a/src/metronome/types/v1/plan_get_details_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel -from .plan_detail import PlanDetail - -__all__ = ["PlanGetDetailsResponse"] - - -class PlanGetDetailsResponse(BaseModel): - data: PlanDetail diff --git a/src/metronome/types/v1/plan_list_charges_params.py b/src/metronome/types/v1/plan_list_charges_params.py deleted file mode 100644 index 08b4eead5..000000000 --- a/src/metronome/types/v1/plan_list_charges_params.py +++ /dev/null @@ -1,17 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["PlanListChargesParams"] - - -class PlanListChargesParams(TypedDict, total=False): - plan_id: Required[str] - - limit: int - """Max number of results that should be returned""" - - next_page: str - """Cursor that indicates where the next page of results should start.""" diff --git a/src/metronome/types/v1/plan_list_charges_response.py b/src/metronome/types/v1/plan_list_charges_response.py deleted file mode 100644 index 9e1aaf306..000000000 --- a/src/metronome/types/v1/plan_list_charges_response.py +++ /dev/null @@ -1,72 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from typing_extensions import Literal - -from ..._models import BaseModel -from ..shared.credit_type_data import CreditTypeData - -__all__ = ["PlanListChargesResponse", "Price", "UnitConversion"] - - -class Price(BaseModel): - tier: float - """Used in pricing tiers. Indicates at what metric value the price applies.""" - - value: float - - collection_interval: Optional[float] = None - - collection_schedule: Optional[str] = None - - quantity: Optional[float] = None - - -class UnitConversion(BaseModel): - """Specifies how quantities for usage based charges will be converted.""" - - division_factor: float - """The conversion factor""" - - rounding_behavior: Optional[Literal["floor", "ceiling"]] = None - """Whether usage should be rounded down or up to the nearest whole number. - - If null, quantity will be rounded to 20 decimal places. - """ - - -class PlanListChargesResponse(BaseModel): - id: str - - charge_type: Literal["usage", "fixed", "composite", "minimum", "seat"] - - credit_type: CreditTypeData - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - name: str - - prices: List[Price] - - product_id: str - - product_name: str - - quantity: Optional[float] = None - - start_period: Optional[float] = None - """Used in price ramps. - - Indicates how many billing periods pass before the charge applies. - """ - - tier_reset_frequency: Optional[float] = None - """Used in pricing tiers. - - Indicates how often the tier resets. Default is 1 - the tier count resets every - billing period. - """ - - unit_conversion: Optional[UnitConversion] = None - """Specifies how quantities for usage based charges will be converted.""" diff --git a/src/metronome/types/v1/plan_list_customers_params.py b/src/metronome/types/v1/plan_list_customers_params.py deleted file mode 100644 index 0acc7a27a..000000000 --- a/src/metronome/types/v1/plan_list_customers_params.py +++ /dev/null @@ -1,29 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["PlanListCustomersParams"] - - -class PlanListCustomersParams(TypedDict, total=False): - plan_id: Required[str] - - limit: int - """Max number of results that should be returned""" - - next_page: str - """Cursor that indicates where the next page of results should start.""" - - status: Literal["all", "active", "ended", "upcoming"] - """Status of customers on a given plan. Defaults to `active`. - - - `all` - Return current, past, and upcoming customers of the plan. - - `active` - Return current customers of the plan. - - `ended` - Return past customers of the plan. - - `upcoming` - Return upcoming customers of the plan. - - Multiple statuses can be OR'd together using commas, e.g. `active,ended`. - **Note:** `ended,upcoming` combination is not yet supported. - """ diff --git a/src/metronome/types/v1/plan_list_customers_response.py b/src/metronome/types/v1/plan_list_customers_response.py deleted file mode 100644 index a6f37e767..000000000 --- a/src/metronome/types/v1/plan_list_customers_response.py +++ /dev/null @@ -1,32 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Optional -from datetime import datetime - -from ..._models import BaseModel -from .customer_detail import CustomerDetail - -__all__ = ["PlanListCustomersResponse", "PlanDetails"] - - -class PlanDetails(BaseModel): - id: str - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - customer_plan_id: str - - name: str - - starting_on: datetime - """The start date of the plan""" - - ending_before: Optional[datetime] = None - """The end date of the plan""" - - -class PlanListCustomersResponse(BaseModel): - customer_details: CustomerDetail - - plan_details: PlanDetails diff --git a/src/metronome/types/v1/plan_list_params.py b/src/metronome/types/v1/plan_list_params.py deleted file mode 100644 index 91c204f83..000000000 --- a/src/metronome/types/v1/plan_list_params.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["PlanListParams"] - - -class PlanListParams(TypedDict, total=False): - limit: int - """Max number of results that should be returned""" - - next_page: str - """Cursor that indicates where the next page of results should start.""" diff --git a/src/metronome/types/v1/plan_list_response.py b/src/metronome/types/v1/plan_list_response.py deleted file mode 100644 index 3db0a83d7..000000000 --- a/src/metronome/types/v1/plan_list_response.py +++ /dev/null @@ -1,18 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Optional - -from ..._models import BaseModel - -__all__ = ["PlanListResponse"] - - -class PlanListResponse(BaseModel): - id: str - - description: str - - name: str - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" diff --git a/src/metronome/types/v1/pricing_unit_list_params.py b/src/metronome/types/v1/pricing_unit_list_params.py deleted file mode 100644 index 8d8983451..000000000 --- a/src/metronome/types/v1/pricing_unit_list_params.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import TypedDict - -__all__ = ["PricingUnitListParams"] - - -class PricingUnitListParams(TypedDict, total=False): - limit: int - """Max number of results that should be returned""" - - next_page: str - """Cursor that indicates where the next page of results should start.""" diff --git a/src/metronome/types/v1/pricing_unit_list_response.py b/src/metronome/types/v1/pricing_unit_list_response.py deleted file mode 100644 index 6be4b911b..000000000 --- a/src/metronome/types/v1/pricing_unit_list_response.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Optional - -from ..._models import BaseModel - -__all__ = ["PricingUnitListResponse"] - - -class PricingUnitListResponse(BaseModel): - id: Optional[str] = None - - is_currency: Optional[bool] = None - - name: Optional[str] = None diff --git a/src/metronome/types/v1/rollover_amount_max_amount_param.py b/src/metronome/types/v1/rollover_amount_max_amount_param.py deleted file mode 100644 index 56e6f77aa..000000000 --- a/src/metronome/types/v1/rollover_amount_max_amount_param.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["RolloverAmountMaxAmountParam"] - - -class RolloverAmountMaxAmountParam(TypedDict, total=False): - type: Required[Literal["MAX_AMOUNT"]] - """Rollover up to a fixed amount of the original credit grant amount.""" - - value: Required[float] - """The maximum amount to rollover.""" diff --git a/src/metronome/types/v1/rollover_amount_max_percentage_param.py b/src/metronome/types/v1/rollover_amount_max_percentage_param.py deleted file mode 100644 index f238a6485..000000000 --- a/src/metronome/types/v1/rollover_amount_max_percentage_param.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["RolloverAmountMaxPercentageParam"] - - -class RolloverAmountMaxPercentageParam(TypedDict, total=False): - type: Required[Literal["MAX_PERCENTAGE"]] - """Rollover up to a percentage of the original credit grant amount.""" - - value: Required[float] - """The maximum percentage (0-1) of the original credit grant to rollover.""" diff --git a/src/metronome/types/v1/service_list_response.py b/src/metronome/types/v1/service_list_response.py deleted file mode 100644 index 0b6b09f4b..000000000 --- a/src/metronome/types/v1/service_list_response.py +++ /dev/null @@ -1,20 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List -from typing_extensions import Literal - -from ..._models import BaseModel - -__all__ = ["ServiceListResponse", "Service"] - - -class Service(BaseModel): - ips: List[str] - - name: str - - usage: Literal["makes_connections_from", "accepts_connections_at"] - - -class ServiceListResponse(BaseModel): - services: List[Service] diff --git a/src/metronome/types/v1/setting_upsert_avalara_credentials_params.py b/src/metronome/types/v1/setting_upsert_avalara_credentials_params.py deleted file mode 100644 index bcabba4d9..000000000 --- a/src/metronome/types/v1/setting_upsert_avalara_credentials_params.py +++ /dev/null @@ -1,32 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Literal, Required, TypedDict - -from ..._types import SequenceNotStr - -__all__ = ["SettingUpsertAvalaraCredentialsParams"] - - -class SettingUpsertAvalaraCredentialsParams(TypedDict, total=False): - avalara_environment: Required[Literal["PRODUCTION", "SANDBOX"]] - """The Avalara environment to use (SANDBOX or PRODUCTION).""" - - avalara_password: Required[str] - """The password for the Avalara account.""" - - avalara_username: Required[str] - """The username for the Avalara account.""" - - delivery_method_ids: Required[SequenceNotStr[str]] - """ - The delivery method IDs of the billing provider configurations to update, can be - found in the response of the `/listConfiguredBillingProviders` endpoint. - """ - - commit_transactions: bool - """ - Commit transactions if you want Metronome tax calculations used for reporting - and tax filings. - """ diff --git a/src/metronome/types/v1/setting_upsert_avalara_credentials_response.py b/src/metronome/types/v1/setting_upsert_avalara_credentials_response.py deleted file mode 100644 index 15e21db53..000000000 --- a/src/metronome/types/v1/setting_upsert_avalara_credentials_response.py +++ /dev/null @@ -1,9 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel - -__all__ = ["SettingUpsertAvalaraCredentialsResponse"] - - -class SettingUpsertAvalaraCredentialsResponse(BaseModel): - pass diff --git a/src/metronome/types/v1/settings/__init__.py b/src/metronome/types/v1/settings/__init__.py deleted file mode 100644 index 089b3ec8f..000000000 --- a/src/metronome/types/v1/settings/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .billing_provider_list_params import BillingProviderListParams as BillingProviderListParams -from .billing_provider_create_params import BillingProviderCreateParams as BillingProviderCreateParams -from .billing_provider_list_response import BillingProviderListResponse as BillingProviderListResponse -from .billing_provider_create_response import BillingProviderCreateResponse as BillingProviderCreateResponse diff --git a/src/metronome/types/v1/settings/billing_provider_create_params.py b/src/metronome/types/v1/settings/billing_provider_create_params.py deleted file mode 100644 index f2732fed6..000000000 --- a/src/metronome/types/v1/settings/billing_provider_create_params.py +++ /dev/null @@ -1,23 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict -from typing_extensions import Literal, Required, TypedDict - -__all__ = ["BillingProviderCreateParams"] - - -class BillingProviderCreateParams(TypedDict, total=False): - billing_provider: Required[Literal["aws_marketplace", "azure_marketplace", "gcp_marketplace"]] - """The billing provider set for this configuration.""" - - configuration: Required[Dict[str, object]] - """Account-level configuration for the billing provider. - - The structure of this object is specific to the billing provider and delivery - provider combination. See examples below. - """ - - delivery_method: Required[Literal["direct_to_billing_provider", "aws_sqs", "aws_sns"]] - """The method to use for delivering invoices for this configuration.""" diff --git a/src/metronome/types/v1/settings/billing_provider_create_response.py b/src/metronome/types/v1/settings/billing_provider_create_response.py deleted file mode 100644 index 05969016e..000000000 --- a/src/metronome/types/v1/settings/billing_provider_create_response.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ...._models import BaseModel - -__all__ = ["BillingProviderCreateResponse", "Data"] - - -class Data(BaseModel): - delivery_method_id: str - - -class BillingProviderCreateResponse(BaseModel): - data: Data diff --git a/src/metronome/types/v1/settings/billing_provider_list_params.py b/src/metronome/types/v1/settings/billing_provider_list_params.py deleted file mode 100644 index 6b061b108..000000000 --- a/src/metronome/types/v1/settings/billing_provider_list_params.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Optional -from typing_extensions import TypedDict - -__all__ = ["BillingProviderListParams"] - - -class BillingProviderListParams(TypedDict, total=False): - next_page: Optional[str] - """The cursor to the next page of results""" diff --git a/src/metronome/types/v1/settings/billing_provider_list_response.py b/src/metronome/types/v1/settings/billing_provider_list_response.py deleted file mode 100644 index 3cde526a0..000000000 --- a/src/metronome/types/v1/settings/billing_provider_list_response.py +++ /dev/null @@ -1,42 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from typing_extensions import Literal - -from ...._models import BaseModel - -__all__ = ["BillingProviderListResponse", "Data"] - - -class Data(BaseModel): - billing_provider: Literal[ - "aws_marketplace", - "stripe", - "netsuite", - "custom", - "azure_marketplace", - "quickbooks_online", - "workday", - "gcp_marketplace", - "metronome", - ] - """The billing provider set for this configuration.""" - - delivery_method: Literal["direct_to_billing_provider", "aws_sqs", "tackle", "aws_sns"] - """The method to use for delivering invoices to this customer.""" - - delivery_method_configuration: Dict[str, object] - """Configuration for the delivery method. - - The structure of this object is specific to the delivery method. Some - configuration may be omitted for security reasons. - """ - - delivery_method_id: str - """ID of the delivery method to use for this customer.""" - - -class BillingProviderListResponse(BaseModel): - data: List[Data] - - next_page: Optional[str] = None diff --git a/src/metronome/types/v1/usage_ingest_params.py b/src/metronome/types/v1/usage_ingest_params.py deleted file mode 100644 index 55ad031bc..000000000 --- a/src/metronome/types/v1/usage_ingest_params.py +++ /dev/null @@ -1,25 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Iterable -from typing_extensions import Required, TypedDict - -__all__ = ["UsageIngestParams", "Usage"] - - -class UsageIngestParams(TypedDict, total=False): - usage: Iterable[Usage] - - -class Usage(TypedDict, total=False): - customer_id: Required[str] - - event_type: Required[str] - - timestamp: Required[str] - """RFC 3339 formatted""" - - transaction_id: Required[str] - - properties: Dict[str, object] diff --git a/src/metronome/types/v1/usage_list_params.py b/src/metronome/types/v1/usage_list_params.py deleted file mode 100644 index a95a361de..000000000 --- a/src/metronome/types/v1/usage_list_params.py +++ /dev/null @@ -1,58 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ..._types import SequenceNotStr -from ..._utils import PropertyInfo - -__all__ = ["UsageListParams", "BillableMetric", "BillableMetricGroupBy"] - - -class UsageListParams(TypedDict, total=False): - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - starting_on: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - window_size: Required[Literal["HOUR", "DAY", "NONE"]] - """ - A window_size of "day" or "hour" will return the usage for the specified period - segmented into daily or hourly aggregates. A window_size of "none" will return a - single usage aggregate for the entirety of the specified period. - """ - - next_page: str - """Cursor that indicates where the next page of results should start.""" - - billable_metrics: Iterable[BillableMetric] - """A list of billable metrics to fetch usage for. - - If absent, all billable metrics will be returned. - """ - - customer_ids: SequenceNotStr[str] - """A list of Metronome customer IDs to fetch usage for. - - If absent, usage for all customers will be returned. - """ - - -class BillableMetricGroupBy(TypedDict, total=False): - key: Required[str] - """The name of the group_by key to use""" - - values: SequenceNotStr[str] - """Values of the group_by key to return in the query. - - If this field is omitted, all available values will be returned, up to a maximum - of 200. - """ - - -class BillableMetric(TypedDict, total=False): - id: Required[str] - - group_by: BillableMetricGroupBy diff --git a/src/metronome/types/v1/usage_list_response.py b/src/metronome/types/v1/usage_list_response.py deleted file mode 100644 index de67f77cf..000000000 --- a/src/metronome/types/v1/usage_list_response.py +++ /dev/null @@ -1,28 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Optional -from datetime import datetime - -from ..._models import BaseModel - -__all__ = ["UsageListResponse"] - - -class UsageListResponse(BaseModel): - billable_metric_id: str - - billable_metric_name: str - - customer_id: str - - end_timestamp: datetime - - start_timestamp: datetime - - value: Optional[float] = None - - groups: Optional[Dict[str, Optional[float]]] = None - """Values will be either a number or null. - - Null indicates that there were no matches for the group_by value. - """ diff --git a/src/metronome/types/v1/usage_list_with_groups_params.py b/src/metronome/types/v1/usage_list_with_groups_params.py deleted file mode 100644 index 103514455..000000000 --- a/src/metronome/types/v1/usage_list_with_groups_params.py +++ /dev/null @@ -1,87 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ..._types import SequenceNotStr -from ..._utils import PropertyInfo - -__all__ = ["UsageListWithGroupsParams", "GroupBy"] - - -class UsageListWithGroupsParams(TypedDict, total=False): - billable_metric_id: Required[str] - - customer_id: Required[str] - - window_size: Required[Literal["HOUR", "DAY", "NONE"]] - """ - A window_size of "day" or "hour" will return the usage for the specified period - segmented into daily or hourly aggregates. A window_size of "none" will return a - single usage aggregate for the entirety of the specified period. - """ - - limit: int - """Max number of results that should be returned""" - - next_page: str - """Cursor that indicates where the next page of results should start.""" - - current_period: bool - """If true, will return the usage for the current billing period. - - Will return an error if the customer is currently uncontracted or starting_on - and ending_before are specified when this is true. - """ - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - - group_by: GroupBy - """Use group_key and group_filters instead. - - Use a single group key to group by. Compound group keys are not supported. - """ - - group_filters: Dict[str, SequenceNotStr[str]] - """Object mapping group keys to arrays of values to filter on. - - Only usage matching these filter values will be returned. Keys must be present - in group_key. Omit a key or use an empty array to include all values for that - dimension. - """ - - group_key: SequenceNotStr[str] - """Group key to group usage by. - - Supports both simple (single key) and compound (multiple keys) group keys. - - For simple group keys, provide a single key e.g. `["region"]`. For compound - group keys, provide multiple keys e.g. `["region", "team"]`. - - For streaming metrics, the keys must be defined as a simple or compound group - key on the billable metric. For compound group keys, all keys must match an - exact compound group key definition — partial matches are not allowed. - - Cannot be used together with `group_by`. - """ - - starting_on: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - - -class GroupBy(TypedDict, total=False): - """Use group_key and group_filters instead. - - Use a single group key to group by. Compound group keys are not supported. - """ - - key: Required[str] - """The name of the group_by key to use""" - - values: SequenceNotStr[str] - """Values of the group_by key to return in the query. - - Omit this if you'd like all values for the key returned. - """ diff --git a/src/metronome/types/v1/usage_list_with_groups_response.py b/src/metronome/types/v1/usage_list_with_groups_response.py deleted file mode 100644 index 56481fa15..000000000 --- a/src/metronome/types/v1/usage_list_with_groups_response.py +++ /dev/null @@ -1,30 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, Optional -from datetime import datetime - -from ..._models import BaseModel - -__all__ = ["UsageListWithGroupsResponse"] - - -class UsageListWithGroupsResponse(BaseModel): - ending_before: datetime - - group_key: Optional[str] = None - """Use `group` instead. The group key for single-key grouping.""" - - group_value: Optional[str] = None - """Use `group` instead. The group value for single-key grouping.""" - - starting_on: datetime - - value: Optional[float] = None - - group: Optional[Dict[str, str]] = None - """ - Map of group key to their value for this usage aggregate. For simple group keys, - this should be a single key e.g. `{"region": "US-East"}` For compound group - keys, this should contain the values of each group key that forms the compound - e.g. `{"region": "US-East", "team": "engineering"}` - """ diff --git a/src/metronome/types/v1/usage_search_params.py b/src/metronome/types/v1/usage_search_params.py deleted file mode 100644 index 714ecc45a..000000000 --- a/src/metronome/types/v1/usage_search_params.py +++ /dev/null @@ -1,15 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, Annotated, TypedDict - -from ..._types import SequenceNotStr -from ..._utils import PropertyInfo - -__all__ = ["UsageSearchParams"] - - -class UsageSearchParams(TypedDict, total=False): - transaction_ids: Required[Annotated[SequenceNotStr[str], PropertyInfo(alias="transactionIds")]] - """The transaction IDs of the events to retrieve""" diff --git a/src/metronome/types/v1/usage_search_response.py b/src/metronome/types/v1/usage_search_response.py deleted file mode 100644 index cb887170e..000000000 --- a/src/metronome/types/v1/usage_search_response.py +++ /dev/null @@ -1,111 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from datetime import datetime -from typing_extensions import Literal, TypeAlias - -from ..._models import BaseModel -from ..shared.property_filter import PropertyFilter -from ..shared.event_type_filter import EventTypeFilter - -__all__ = [ - "UsageSearchResponse", - "UsageSearchResponseItem", - "UsageSearchResponseItemMatchedBillableMetric", - "UsageSearchResponseItemMatchedCustomer", -] - - -class UsageSearchResponseItemMatchedBillableMetric(BaseModel): - id: str - - name: str - - aggregate: Optional[str] = None - """(DEPRECATED) use aggregation_type instead""" - - aggregate_keys: Optional[List[str]] = None - """(DEPRECATED) use aggregation_key instead""" - - aggregation_key: Optional[str] = None - """A key that specifies which property of the event is used to aggregate data. - - This key must be one of the property filter names and is not applicable when the - aggregation type is 'count'. - """ - - aggregation_type: Optional[Literal["COUNT", "LATEST", "MAX", "SUM", "UNIQUE", "custom_sql"]] = None - """Specifies the type of aggregation performed on matching events. - - Includes "custom_sql" for events search endpoint responses. - """ - - archived_at: Optional[datetime] = None - """RFC 3339 timestamp indicating when the billable metric was archived. - - If not provided, the billable metric is not archived. - """ - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - event_type_filter: Optional[EventTypeFilter] = None - """An optional filtering rule to match the 'event_type' property of an event.""" - - filter: Optional[Dict[str, object]] = None - """(DEPRECATED) use property_filters & event_type_filter instead""" - - group_by: Optional[List[str]] = None - """(DEPRECATED) use group_keys instead""" - - group_keys: Optional[List[List[str]]] = None - """Property names that are used to group usage costs on an invoice. - - Each entry represents a set of properties used to slice events into distinct - buckets. - """ - - property_filters: Optional[List[PropertyFilter]] = None - """A list of filters to match events to this billable metric. - - Each filter defines a rule on an event property. All rules must pass for the - event to match the billable metric. - """ - - sql: Optional[str] = None - """The SQL query associated with the billable metric""" - - -class UsageSearchResponseItemMatchedCustomer(BaseModel): - """The customer the event was matched to if a match was found""" - - id: Optional[str] = None - - name: Optional[str] = None - - -class UsageSearchResponseItem(BaseModel): - id: str - - customer_id: str - """The ID of the customer in the ingest event body""" - - event_type: str - - timestamp: datetime - - transaction_id: str - - is_duplicate: Optional[bool] = None - - matched_billable_metrics: Optional[List[UsageSearchResponseItemMatchedBillableMetric]] = None - - matched_customer: Optional[UsageSearchResponseItemMatchedCustomer] = None - """The customer the event was matched to if a match was found""" - - processed_at: Optional[datetime] = None - - properties: Optional[Dict[str, object]] = None - - -UsageSearchResponse: TypeAlias = List[UsageSearchResponseItem] diff --git a/src/metronome/types/v2/__init__.py b/src/metronome/types/v2/__init__.py deleted file mode 100644 index b28ab986d..000000000 --- a/src/metronome/types/v2/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from .contract_edit_params import ContractEditParams as ContractEditParams -from .contract_list_params import ContractListParams as ContractListParams -from .contract_edit_response import ContractEditResponse as ContractEditResponse -from .contract_list_response import ContractListResponse as ContractListResponse -from .contract_retrieve_params import ContractRetrieveParams as ContractRetrieveParams -from .contract_retrieve_response import ContractRetrieveResponse as ContractRetrieveResponse -from .contract_edit_commit_params import ContractEditCommitParams as ContractEditCommitParams -from .contract_edit_credit_params import ContractEditCreditParams as ContractEditCreditParams -from .contract_edit_commit_response import ContractEditCommitResponse as ContractEditCommitResponse -from .contract_edit_credit_response import ContractEditCreditResponse as ContractEditCreditResponse -from .contract_get_edit_history_params import ContractGetEditHistoryParams as ContractGetEditHistoryParams -from .contract_get_edit_history_response import ContractGetEditHistoryResponse as ContractGetEditHistoryResponse diff --git a/src/metronome/types/v2/contract_edit_commit_params.py b/src/metronome/types/v2/contract_edit_commit_params.py deleted file mode 100644 index 77a0b5991..000000000 --- a/src/metronome/types/v2/contract_edit_commit_params.py +++ /dev/null @@ -1,151 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable, Optional -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ..._types import SequenceNotStr -from ..._utils import PropertyInfo -from ..shared_params.commit_specifier_input import CommitSpecifierInput -from ..shared_params.commit_hierarchy_configuration import CommitHierarchyConfiguration - -__all__ = [ - "ContractEditCommitParams", - "AccessSchedule", - "AccessScheduleAddScheduleItem", - "AccessScheduleRemoveScheduleItem", - "AccessScheduleUpdateScheduleItem", - "InvoiceSchedule", - "InvoiceScheduleAddScheduleItem", - "InvoiceScheduleRemoveScheduleItem", - "InvoiceScheduleUpdateScheduleItem", -] - - -class ContractEditCommitParams(TypedDict, total=False): - commit_id: Required[str] - """ID of the commit to edit""" - - customer_id: Required[str] - """ID of the customer whose commit is being edited""" - - access_schedule: AccessSchedule - - applicable_product_ids: Optional[SequenceNotStr[str]] - """Which products the commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - applicable_product_tags: Optional[SequenceNotStr[str]] - """Which tags the commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - description: str - """Updated description for the commit""" - - hierarchy_configuration: CommitHierarchyConfiguration - """Optional configuration for commit hierarchy access control""" - - invoice_contract_id: str - """ID of contract to use for invoicing""" - - invoice_schedule: InvoiceSchedule - - name: str - """Updated name for the commit""" - - priority: Optional[float] - """ - If multiple commits are applicable, the one with the lower priority will apply - first. - """ - - product_id: str - - rate_type: Literal["LIST_RATE", "COMMIT_RATE"] - """ - If provided, updates the commit to use the specified rate type for current and - future invoices. Previously finalized invoices will need to be voided and - regenerated to reflect the rate type change. - """ - - specifiers: Optional[Iterable[CommitSpecifierInput]] - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - Instead, to target usage by product or product tag, pass those values in the - body of `specifiers`. - """ - - -class AccessScheduleAddScheduleItem(TypedDict, total=False): - amount: Required[float] - - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - -class AccessScheduleRemoveScheduleItem(TypedDict, total=False): - id: Required[str] - - -class AccessScheduleUpdateScheduleItem(TypedDict, total=False): - id: Required[str] - - amount: float - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - - starting_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - - -class AccessSchedule(TypedDict, total=False): - add_schedule_items: Iterable[AccessScheduleAddScheduleItem] - - remove_schedule_items: Iterable[AccessScheduleRemoveScheduleItem] - - update_schedule_items: Iterable[AccessScheduleUpdateScheduleItem] - - -class InvoiceScheduleAddScheduleItem(TypedDict, total=False): - timestamp: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - amount: float - - quantity: float - - unit_price: float - - -class InvoiceScheduleRemoveScheduleItem(TypedDict, total=False): - id: Required[str] - - -class InvoiceScheduleUpdateScheduleItem(TypedDict, total=False): - id: Required[str] - - amount: float - - quantity: float - - timestamp: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - - unit_price: float - - -class InvoiceSchedule(TypedDict, total=False): - add_schedule_items: Iterable[InvoiceScheduleAddScheduleItem] - - remove_schedule_items: Iterable[InvoiceScheduleRemoveScheduleItem] - - update_schedule_items: Iterable[InvoiceScheduleUpdateScheduleItem] diff --git a/src/metronome/types/v2/contract_edit_commit_response.py b/src/metronome/types/v2/contract_edit_commit_response.py deleted file mode 100644 index df308d728..000000000 --- a/src/metronome/types/v2/contract_edit_commit_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel -from ..shared.id import ID - -__all__ = ["ContractEditCommitResponse"] - - -class ContractEditCommitResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v2/contract_edit_credit_params.py b/src/metronome/types/v2/contract_edit_credit_params.py deleted file mode 100644 index dc15b7673..000000000 --- a/src/metronome/types/v2/contract_edit_credit_params.py +++ /dev/null @@ -1,108 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union, Iterable, Optional -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ..._types import SequenceNotStr -from ..._utils import PropertyInfo -from ..shared_params.commit_specifier_input import CommitSpecifierInput -from ..shared_params.commit_hierarchy_configuration import CommitHierarchyConfiguration - -__all__ = [ - "ContractEditCreditParams", - "AccessSchedule", - "AccessScheduleAddScheduleItem", - "AccessScheduleRemoveScheduleItem", - "AccessScheduleUpdateScheduleItem", -] - - -class ContractEditCreditParams(TypedDict, total=False): - credit_id: Required[str] - """ID of the credit to edit""" - - customer_id: Required[str] - """ID of the customer whose credit is being edited""" - - access_schedule: AccessSchedule - - applicable_product_ids: Optional[SequenceNotStr[str]] - """Which products the credit applies to. - - If both applicable_product_ids and applicable_product_tags are not provided, the - credit applies to all products. - """ - - applicable_product_tags: Optional[SequenceNotStr[str]] - """Which tags the credit applies to. - - If both applicable_product_ids and applicable_product_tags are not provided, the - credit applies to all products. - """ - - description: str - """Updated description for the credit""" - - hierarchy_configuration: CommitHierarchyConfiguration - """Optional configuration for credit hierarchy access control""" - - name: str - """Updated name for the credit""" - - priority: Optional[float] - """ - If multiple commits are applicable, the one with the lower priority will apply - first. - """ - - product_id: str - - rate_type: Literal["LIST_RATE", "COMMIT_RATE"] - """ - If provided, updates the credit to use the specified rate type for current and - future invoices. Previously finalized invoices will need to be voided and - regenerated to reflect the rate type change. - """ - - specifiers: Optional[Iterable[CommitSpecifierInput]] - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - Instead, to target usage by product or product tag, pass those values in the - body of `specifiers`. - """ - - -class AccessScheduleAddScheduleItem(TypedDict, total=False): - amount: Required[float] - - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - -class AccessScheduleRemoveScheduleItem(TypedDict, total=False): - id: Required[str] - - -class AccessScheduleUpdateScheduleItem(TypedDict, total=False): - id: Required[str] - - amount: float - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - - starting_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - - -class AccessSchedule(TypedDict, total=False): - add_schedule_items: Iterable[AccessScheduleAddScheduleItem] - - remove_schedule_items: Iterable[AccessScheduleRemoveScheduleItem] - - update_schedule_items: Iterable[AccessScheduleUpdateScheduleItem] diff --git a/src/metronome/types/v2/contract_edit_credit_response.py b/src/metronome/types/v2/contract_edit_credit_response.py deleted file mode 100644 index 478a02e04..000000000 --- a/src/metronome/types/v2/contract_edit_credit_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel -from ..shared.id import ID - -__all__ = ["ContractEditCreditResponse"] - - -class ContractEditCreditResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v2/contract_edit_params.py b/src/metronome/types/v2/contract_edit_params.py deleted file mode 100644 index 39edcdb5c..000000000 --- a/src/metronome/types/v2/contract_edit_params.py +++ /dev/null @@ -1,1907 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Dict, Union, Iterable, Optional -from datetime import datetime -from typing_extensions import Literal, Required, Annotated, TypedDict - -from ..._types import SequenceNotStr -from ..._utils import PropertyInfo -from ..shared_params.tier import Tier -from ..shared_params.commit_specifier_input import CommitSpecifierInput -from ..shared_params.payment_gate_config_v2 import PaymentGateConfigV2 -from ..shared_params.update_base_threshold_commit import UpdateBaseThresholdCommit -from ..shared_params.commit_hierarchy_configuration import CommitHierarchyConfiguration -from ..shared_params.spend_threshold_configuration_v2 import SpendThresholdConfigurationV2 -from ..shared_params.prepaid_balance_threshold_configuration_v2 import PrepaidBalanceThresholdConfigurationV2 - -__all__ = [ - "ContractEditParams", - "AddBillingProviderConfigurationUpdate", - "AddBillingProviderConfigurationUpdateBillingProviderConfiguration", - "AddBillingProviderConfigurationUpdateSchedule", - "AddCommit", - "AddCommitAccessSchedule", - "AddCommitAccessScheduleScheduleItem", - "AddCommitInvoiceSchedule", - "AddCommitInvoiceScheduleRecurringSchedule", - "AddCommitInvoiceScheduleScheduleItem", - "AddCommitPaymentGateConfig", - "AddCommitPaymentGateConfigPrecalculatedTaxConfig", - "AddCommitPaymentGateConfigStripeConfig", - "AddCredit", - "AddCreditAccessSchedule", - "AddCreditAccessScheduleScheduleItem", - "AddDiscount", - "AddDiscountSchedule", - "AddDiscountScheduleRecurringSchedule", - "AddDiscountScheduleScheduleItem", - "AddOverride", - "AddOverrideOverrideSpecifier", - "AddOverrideOverwriteRate", - "AddOverrideTier", - "AddProfessionalService", - "AddRecurringCommit", - "AddRecurringCommitAccessAmount", - "AddRecurringCommitCommitDuration", - "AddRecurringCommitInvoiceAmount", - "AddRecurringCommitSubscriptionConfig", - "AddRecurringCommitSubscriptionConfigApplySeatIncreaseConfig", - "AddRecurringCredit", - "AddRecurringCreditAccessAmount", - "AddRecurringCreditCommitDuration", - "AddRecurringCreditSubscriptionConfig", - "AddRecurringCreditSubscriptionConfigApplySeatIncreaseConfig", - "AddResellerRoyalty", - "AddResellerRoyaltyAwsOptions", - "AddResellerRoyaltyGcpOptions", - "AddRevenueSystemConfigurationUpdate", - "AddRevenueSystemConfigurationUpdateRevenueSystemConfiguration", - "AddRevenueSystemConfigurationUpdateSchedule", - "AddScheduledCharge", - "AddScheduledChargeSchedule", - "AddScheduledChargeScheduleRecurringSchedule", - "AddScheduledChargeScheduleScheduleItem", - "AddSubscription", - "AddSubscriptionProration", - "AddSubscriptionSubscriptionRate", - "AddSubscriptionSeatConfig", - "ArchiveCommit", - "ArchiveCredit", - "ArchiveScheduledCharge", - "RemoveOverride", - "UpdateCommit", - "UpdateCommitAccessSchedule", - "UpdateCommitAccessScheduleAddScheduleItem", - "UpdateCommitAccessScheduleRemoveScheduleItem", - "UpdateCommitAccessScheduleUpdateScheduleItem", - "UpdateCommitInvoiceSchedule", - "UpdateCommitInvoiceScheduleAddScheduleItem", - "UpdateCommitInvoiceScheduleRemoveScheduleItem", - "UpdateCommitInvoiceScheduleUpdateScheduleItem", - "UpdateCredit", - "UpdateCreditAccessSchedule", - "UpdateCreditAccessScheduleAddScheduleItem", - "UpdateCreditAccessScheduleRemoveScheduleItem", - "UpdateCreditAccessScheduleUpdateScheduleItem", - "UpdatePrepaidBalanceThresholdConfiguration", - "UpdatePrepaidBalanceThresholdConfigurationCommit", - "UpdateRecurringCommit", - "UpdateRecurringCommitAccessAmount", - "UpdateRecurringCommitInvoiceAmount", - "UpdateRecurringCredit", - "UpdateRecurringCreditAccessAmount", - "UpdateScheduledCharge", - "UpdateScheduledChargeInvoiceSchedule", - "UpdateScheduledChargeInvoiceScheduleAddScheduleItem", - "UpdateScheduledChargeInvoiceScheduleRemoveScheduleItem", - "UpdateScheduledChargeInvoiceScheduleUpdateScheduleItem", - "UpdateSpendThresholdConfiguration", - "UpdateSubscription", - "UpdateSubscriptionQuantityManagementModeUpdate", - "UpdateSubscriptionQuantityManagementModeUpdateSeatConfig", - "UpdateSubscriptionQuantityUpdate", - "UpdateSubscriptionSeatUpdates", - "UpdateSubscriptionSeatUpdatesAddSeatID", - "UpdateSubscriptionSeatUpdatesAddUnassignedSeat", - "UpdateSubscriptionSeatUpdatesRemoveSeatID", - "UpdateSubscriptionSeatUpdatesRemoveUnassignedSeat", -] - - -class ContractEditParams(TypedDict, total=False): - contract_id: Required[str] - """ID of the contract being edited""" - - customer_id: Required[str] - """ID of the customer whose contract is being edited""" - - add_billing_provider_configuration_update: AddBillingProviderConfigurationUpdate - """Update the billing provider configuration on the contract. - - Currently only supports adding a billing provider configuration to a contract - that does not already have one. - """ - - add_commits: Iterable[AddCommit] - - add_credits: Iterable[AddCredit] - - add_discounts: Iterable[AddDiscount] - - add_overrides: Iterable[AddOverride] - - add_prepaid_balance_threshold_configuration: PrepaidBalanceThresholdConfigurationV2 - - add_professional_services: Iterable[AddProfessionalService] - """This field's availability is dependent on your client's configuration.""" - - add_recurring_commits: Iterable[AddRecurringCommit] - - add_recurring_credits: Iterable[AddRecurringCredit] - - add_reseller_royalties: Iterable[AddResellerRoyalty] - - add_revenue_system_configuration_update: AddRevenueSystemConfigurationUpdate - """Update the revenue system configuration on the contract. - - Currently only supports adding a revenue system configuration to a contract that - does not already have one. - """ - - add_scheduled_charges: Iterable[AddScheduledCharge] - - add_spend_threshold_configuration: SpendThresholdConfigurationV2 - - add_subscriptions: Iterable[AddSubscription] - """ - Optional list of - [subscriptions](https://docs.metronome.com/manage-product-access/create-subscription/) - to add to the contract. - """ - - allow_contract_ending_before_finalized_invoice: bool - """ - If true, allows setting the contract end date earlier than the end_timestamp of - existing finalized invoices. Finalized invoices will be unchanged; if you want - to incorporate the new end date, you can void and regenerate finalized usage - invoices. Defaults to true. - """ - - archive_commits: Iterable[ArchiveCommit] - """IDs of commits to archive""" - - archive_credits: Iterable[ArchiveCredit] - """IDs of credits to archive""" - - archive_scheduled_charges: Iterable[ArchiveScheduledCharge] - """IDs of scheduled charges to archive""" - - remove_overrides: Iterable[RemoveOverride] - """IDs of overrides to remove""" - - uniqueness_key: str - """Optional uniqueness key to prevent duplicate contract edits.""" - - update_commits: Iterable[UpdateCommit] - - update_contract_end_date: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] - """RFC 3339 timestamp indicating when the contract will end (exclusive).""" - - update_contract_name: Optional[str] - """Value to update the contract name to. - - If not provided, the contract name will remain unchanged. - """ - - update_credits: Iterable[UpdateCredit] - - update_net_payment_terms_days: Optional[float] - """Number of days after issuance of invoice after which the invoice is due (e.g. - - Net 30). - """ - - update_prepaid_balance_threshold_configuration: UpdatePrepaidBalanceThresholdConfiguration - - update_recurring_commits: Iterable[UpdateRecurringCommit] - """ - Edits to these recurring commits will only affect commits whose access schedules - has not started. Expired commits, and commits with an active access schedule - will remain unchanged. - """ - - update_recurring_credits: Iterable[UpdateRecurringCredit] - """ - Edits to these recurring credits will only affect credits whose access schedules - has not started. Expired credits, and credits with an active access schedule - will remain unchanged. - """ - - update_scheduled_charges: Iterable[UpdateScheduledCharge] - - update_spend_threshold_configuration: UpdateSpendThresholdConfiguration - - update_subscriptions: Iterable[UpdateSubscription] - """Optional list of subscriptions to update.""" - - -class AddBillingProviderConfigurationUpdateBillingProviderConfiguration(TypedDict, total=False): - billing_provider: Literal[ - "aws_marketplace", - "stripe", - "netsuite", - "custom", - "azure_marketplace", - "quickbooks_online", - "workday", - "gcp_marketplace", - "metronome", - ] - - billing_provider_configuration_id: str - - delivery_method: Literal["direct_to_billing_provider", "aws_sqs", "tackle", "aws_sns"] - - -class AddBillingProviderConfigurationUpdateSchedule(TypedDict, total=False): - """Indicates when the billing provider will be active on the contract. - - Any charges accrued during the schedule will be billed to the indicated billing provider. - """ - - effective_at: Required[Literal["START_OF_CURRENT_PERIOD"]] - """When the billing provider update will take effect.""" - - -class AddBillingProviderConfigurationUpdate(TypedDict, total=False): - """Update the billing provider configuration on the contract. - - Currently only supports adding a billing provider configuration to a contract that does not already have one. - """ - - billing_provider_configuration: Required[AddBillingProviderConfigurationUpdateBillingProviderConfiguration] - - schedule: Required[AddBillingProviderConfigurationUpdateSchedule] - """Indicates when the billing provider will be active on the contract. - - Any charges accrued during the schedule will be billed to the indicated billing - provider. - """ - - -class AddCommitAccessScheduleScheduleItem(TypedDict, total=False): - amount: Required[float] - - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (exclusive)""" - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (inclusive)""" - - -class AddCommitAccessSchedule(TypedDict, total=False): - """Required: Schedule for distributing the commit to the customer. - - For "POSTPAID" commits only one schedule item is allowed and amount must match invoice_schedule total. - """ - - schedule_items: Required[Iterable[AddCommitAccessScheduleScheduleItem]] - - credit_type_id: str - - -class AddCommitInvoiceScheduleRecurringSchedule(TypedDict, total=False): - """Enter the unit price and quantity for the charge or instead only send the amount. - - If amount is sent, the unit price is assumed to be the amount and quantity is inferred to be 1. - """ - - amount_distribution: Required[Literal["DIVIDED", "DIVIDED_ROUNDED", "EACH"]] - - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (exclusive).""" - - frequency: Required[Literal["MONTHLY", "QUARTERLY", "SEMI_ANNUAL", "ANNUAL", "WEEKLY"]] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (inclusive).""" - - amount: float - """Amount for the charge. - - Can be provided instead of unit_price and quantity. If amount is sent, the - unit_price is assumed to be the amount and quantity is inferred to be 1. - """ - - quantity: float - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount and must be specified - with unit_price. If specified amount cannot be provided. - """ - - unit_price: float - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified - with quantity. If specified amount cannot be provided. - """ - - -class AddCommitInvoiceScheduleScheduleItem(TypedDict, total=False): - timestamp: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """timestamp of the scheduled event""" - - amount: float - """Amount for the charge. - - Can be provided instead of unit_price and quantity. If amount is sent, the - unit_price is assumed to be the amount and quantity is inferred to be 1. - """ - - quantity: float - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount and must be specified - with unit_price. If specified amount cannot be provided. - """ - - unit_price: float - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified - with quantity. If specified amount cannot be provided. - """ - - -class AddCommitInvoiceSchedule(TypedDict, total=False): - """ - Required for "POSTPAID" commits: the true up invoice will be generated at this time and only one schedule item is allowed; the total must match access_schedule amount. Optional for "PREPAID" commits: if not provided, this will be a "complimentary" commit with no invoice. - """ - - credit_type_id: str - """Defaults to USD (cents) if not passed.""" - - do_not_invoice: bool - """This field is only applicable to commit invoice schedules. - - If true, this schedule will not generate an invoice. - """ - - recurring_schedule: AddCommitInvoiceScheduleRecurringSchedule - """Enter the unit price and quantity for the charge or instead only send the - amount. - - If amount is sent, the unit price is assumed to be the amount and quantity is - inferred to be 1. - """ - - schedule_items: Iterable[AddCommitInvoiceScheduleScheduleItem] - """Either provide amount or provide both unit_price and quantity.""" - - -class AddCommitPaymentGateConfigPrecalculatedTaxConfig(TypedDict, total=False): - """Only applicable if using PRECALCULATED as your tax type.""" - - tax_amount: Required[float] - """Amount of tax to be applied. - - This should be in the same currency and denomination as the commit's invoice - schedule - """ - - tax_name: str - """Name of the tax to be applied. - - This may be used in an invoice line item description. - """ - - -class AddCommitPaymentGateConfigStripeConfig(TypedDict, total=False): - """Only applicable if using STRIPE as your payment gateway type.""" - - payment_type: Required[Literal["INVOICE", "PAYMENT_INTENT"]] - """If left blank, will default to INVOICE""" - - invoice_metadata: Dict[str, str] - """Metadata to be added to the Stripe invoice. - - Only applicable if using INVOICE as your payment type. - """ - - on_session_payment: bool - """If true, the payment will be made assuming the customer is present (i.e. - - on session). - - If false, the payment will be made assuming the customer is not present (i.e. - off session). For cardholders from a country with an e-mandate requirement (e.g. - India), the payment may be declined. - - If left blank, will default to false. - """ - - -class AddCommitPaymentGateConfig(TypedDict, total=False): - """optionally payment gate this commit""" - - payment_gate_type: Required[Literal["NONE", "STRIPE", "EXTERNAL"]] - """Gate access to the commit balance based on successful collection of payment. - - Select STRIPE for Metronome to facilitate payment via Stripe. Select EXTERNAL to - facilitate payment using your own payment integration. Select NONE if you do not - wish to payment gate the commit balance. - """ - - precalculated_tax_config: AddCommitPaymentGateConfigPrecalculatedTaxConfig - """Only applicable if using PRECALCULATED as your tax type.""" - - stripe_config: AddCommitPaymentGateConfigStripeConfig - """Only applicable if using STRIPE as your payment gateway type.""" - - tax_type: Literal["NONE", "STRIPE", "ANROK", "PRECALCULATED"] - """Stripe tax is only supported for Stripe payment gateway. - - Select NONE if you do not wish Metronome to calculate tax on your behalf. - Leaving this field blank will default to NONE. - """ - - -class AddCommit(TypedDict, total=False): - product_id: Required[str] - - type: Required[Literal["PREPAID", "POSTPAID"]] - - access_schedule: AddCommitAccessSchedule - """Required: Schedule for distributing the commit to the customer. - - For "POSTPAID" commits only one schedule item is allowed and amount must match - invoice_schedule total. - """ - - amount: float - """(DEPRECATED) Use access_schedule and invoice_schedule instead.""" - - applicable_product_ids: SequenceNotStr[str] - """Which products the commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - applicable_product_tags: SequenceNotStr[str] - """Which tags the commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: str - """Used only in UI/API. It is not exposed to end customers.""" - - hierarchy_configuration: CommitHierarchyConfiguration - """Optional configuration for commit hierarchy access control""" - - invoice_schedule: AddCommitInvoiceSchedule - """ - Required for "POSTPAID" commits: the true up invoice will be generated at this - time and only one schedule item is allowed; the total must match access_schedule - amount. Optional for "PREPAID" commits: if not provided, this will be a - "complimentary" commit with no invoice. - """ - - name: str - """displayed on invoices""" - - netsuite_sales_order_id: str - """This field's availability is dependent on your client's configuration.""" - - payment_gate_config: AddCommitPaymentGateConfig - """optionally payment gate this commit""" - - priority: float - """ - If multiple commits are applicable, the one with the lower priority will apply - first. - """ - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - - rollover_fraction: float - """Fraction of unused segments that will be rolled over. Must be between 0 and 1.""" - - specifiers: Iterable[CommitSpecifierInput] - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - Instead, to target usage by product or product tag, pass those values in the - body of `specifiers`. - """ - - temporary_id: str - """ - A temporary ID for the commit that can be used to reference the commit for - commit specific overrides. - """ - - -class AddCreditAccessScheduleScheduleItem(TypedDict, total=False): - amount: Required[float] - - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (exclusive)""" - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (inclusive)""" - - -class AddCreditAccessSchedule(TypedDict, total=False): - """Schedule for distributing the credit to the customer.""" - - schedule_items: Required[Iterable[AddCreditAccessScheduleScheduleItem]] - - credit_type_id: str - - -class AddCredit(TypedDict, total=False): - access_schedule: Required[AddCreditAccessSchedule] - """Schedule for distributing the credit to the customer.""" - - product_id: Required[str] - - applicable_product_ids: SequenceNotStr[str] - """Which products the credit applies to. - - If both applicable_product_ids and applicable_product_tags are not provided, the - credit applies to all products. - """ - - applicable_product_tags: SequenceNotStr[str] - """Which tags the credit applies to. - - If both applicable_product_ids and applicable_product_tags are not provided, the - credit applies to all products. - """ - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: str - """Used only in UI/API. It is not exposed to end customers.""" - - hierarchy_configuration: CommitHierarchyConfiguration - """Optional configuration for credit hierarchy access control""" - - name: str - """displayed on invoices""" - - netsuite_sales_order_id: str - """This field's availability is dependent on your client's configuration.""" - - priority: float - """ - If multiple credits are applicable, the one with the lower priority will apply - first. - """ - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - - rollover_fraction: float - """Fraction of unused segments that will be rolled over. Must be between 0 and 1.""" - - specifiers: Iterable[CommitSpecifierInput] - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - Instead, to target usage by product or product tag, pass those values in the - body of `specifiers`. - """ - - -class AddDiscountScheduleRecurringSchedule(TypedDict, total=False): - """Enter the unit price and quantity for the charge or instead only send the amount. - - If amount is sent, the unit price is assumed to be the amount and quantity is inferred to be 1. - """ - - amount_distribution: Required[Literal["DIVIDED", "DIVIDED_ROUNDED", "EACH"]] - - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (exclusive).""" - - frequency: Required[Literal["MONTHLY", "QUARTERLY", "SEMI_ANNUAL", "ANNUAL", "WEEKLY"]] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (inclusive).""" - - amount: float - """Amount for the charge. - - Can be provided instead of unit_price and quantity. If amount is sent, the - unit_price is assumed to be the amount and quantity is inferred to be 1. - """ - - quantity: float - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount and must be specified - with unit_price. If specified amount cannot be provided. - """ - - unit_price: float - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified - with quantity. If specified amount cannot be provided. - """ - - -class AddDiscountScheduleScheduleItem(TypedDict, total=False): - timestamp: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """timestamp of the scheduled event""" - - amount: float - """Amount for the charge. - - Can be provided instead of unit_price and quantity. If amount is sent, the - unit_price is assumed to be the amount and quantity is inferred to be 1. - """ - - quantity: float - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount and must be specified - with unit_price. If specified amount cannot be provided. - """ - - unit_price: float - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified - with quantity. If specified amount cannot be provided. - """ - - -class AddDiscountSchedule(TypedDict, total=False): - """Must provide either schedule_items or recurring_schedule.""" - - credit_type_id: str - """Defaults to USD (cents) if not passed.""" - - do_not_invoice: bool - """This field is only applicable to commit invoice schedules. - - If true, this schedule will not generate an invoice. - """ - - recurring_schedule: AddDiscountScheduleRecurringSchedule - """Enter the unit price and quantity for the charge or instead only send the - amount. - - If amount is sent, the unit price is assumed to be the amount and quantity is - inferred to be 1. - """ - - schedule_items: Iterable[AddDiscountScheduleScheduleItem] - """Either provide amount or provide both unit_price and quantity.""" - - -class AddDiscount(TypedDict, total=False): - product_id: Required[str] - - schedule: Required[AddDiscountSchedule] - """Must provide either schedule_items or recurring_schedule.""" - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - name: str - """displayed on invoices""" - - netsuite_sales_order_id: str - """This field's availability is dependent on your client's configuration.""" - - -class AddOverrideOverrideSpecifier(TypedDict, total=False): - billing_frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"] - - commit_ids: SequenceNotStr[str] - """If provided, the override will only apply to the specified commits. - - Can only be used for commit specific overrides. If not provided, the override - will apply to all commits. - """ - - presentation_group_values: Dict[str, str] - """A map of group names to values. - - The override will only apply to line items with the specified presentation group - values. Can only be used for multiplier overrides. - """ - - pricing_group_values: Dict[str, str] - """A map of pricing group names to values. - - The override will only apply to products with the specified pricing group - values. - """ - - product_id: str - """If provided, the override will only apply to the product with the specified ID.""" - - product_tags: SequenceNotStr[str] - """ - If provided, the override will only apply to products with all the specified - tags. - """ - - recurring_commit_ids: SequenceNotStr[str] - """Can only be used for commit specific overrides. - - Must be used in conjunction with one of product_id, product_tags, - pricing_group_values, or presentation_group_values. If provided, the override - will only apply to commits created by the specified recurring commit ids. - """ - - recurring_credit_ids: SequenceNotStr[str] - """Can only be used for commit specific overrides. - - Must be used in conjunction with one of product_id, product_tags, - pricing_group_values, or presentation_group_values. If provided, the override - will only apply to commits created by the specified recurring credit ids. - """ - - -class AddOverrideOverwriteRate(TypedDict, total=False): - """Required for OVERWRITE type.""" - - rate_type: Required[Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "TIERED", "TIERED_PERCENTAGE", "CUSTOM"]] - - credit_type_id: str - - custom_rate: Dict[str, object] - """Only set for CUSTOM rate_type. - - This field is interpreted by custom rate processors. - """ - - is_prorated: bool - """Default proration configuration. - - Only valid for SUBSCRIPTION rate_type. Must be set to true. - """ - - price: float - """Default price. - - For FLAT rate_type, this must be >=0. For PERCENTAGE rate_type, this is a - decimal fraction, e.g. use 0.1 for 10%; this must be >=0 and <=1. - """ - - quantity: float - """Default quantity. For SUBSCRIPTION rate_type, this must be >=0.""" - - tiers: Iterable[Tier] - """Only set for TIERED rate_type.""" - - -class AddOverrideTier(TypedDict, total=False): - multiplier: Required[float] - - size: float - - -class AddOverride(TypedDict, total=False): - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp indicating when the override will start applying (inclusive)""" - - applicable_product_tags: SequenceNotStr[str] - """tags identifying products whose rates are being overridden""" - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """RFC 3339 timestamp indicating when the override will stop applying (exclusive)""" - - entitled: bool - - is_commit_specific: bool - """Indicates whether the override should only apply to commits. - - Defaults to `false`. If `true`, you can specify relevant commits in - `override_specifiers` by passing `commit_ids`. - """ - - multiplier: float - """Required for MULTIPLIER type. Must be >=0.""" - - override_specifiers: Iterable[AddOverrideOverrideSpecifier] - """Cannot be used in conjunction with product_id or applicable_product_tags. - - If provided, the override will apply to all products with the specified - specifiers. - """ - - overwrite_rate: AddOverrideOverwriteRate - """Required for OVERWRITE type.""" - - priority: float - """Required for EXPLICIT multiplier prioritization scheme and all TIERED overrides. - - Under EXPLICIT prioritization, overwrites are prioritized first, and then tiered - and multiplier overrides are prioritized by their priority value (lowest first). - Must be > 0. - """ - - product_id: str - """ID of the product whose rate is being overridden""" - - target: Literal["COMMIT_RATE", "LIST_RATE"] - """Indicates whether the override applies to commit rates or list rates. - - Can only be used for overrides that have `is_commit_specific` set to `true`. - Defaults to `"LIST_RATE"`. - """ - - tiers: Iterable[AddOverrideTier] - """Required for TIERED type. Must have at least one tier.""" - - type: Literal["OVERWRITE", "MULTIPLIER", "TIERED"] - """Overwrites are prioritized over multipliers and tiered overrides.""" - - -class AddProfessionalService(TypedDict, total=False): - max_amount: Required[float] - """Maximum amount for the term.""" - - product_id: Required[str] - - quantity: Required[float] - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount. - """ - - unit_price: Required[float] - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified. - """ - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: str - - netsuite_sales_order_id: str - """This field's availability is dependent on your client's configuration.""" - - -class AddRecurringCommitAccessAmount(TypedDict, total=False): - """The amount of commit to grant.""" - - credit_type_id: Required[str] - - unit_price: Required[float] - - quantity: float - """ - This field is required unless a subscription is attached via - `subscription_config`. - """ - - -class AddRecurringCommitCommitDuration(TypedDict, total=False): - """Defines the length of the access schedule for each created commit/credit. - - The value represents the number of units. Unit defaults to "PERIODS", where the length of a period is determined by the recurrence_frequency. - """ - - value: Required[float] - - unit: Literal["PERIODS"] - - -class AddRecurringCommitInvoiceAmount(TypedDict, total=False): - """The amount the customer should be billed for the commit. Not required.""" - - credit_type_id: Required[str] - - quantity: Required[float] - - unit_price: Required[float] - - -class AddRecurringCommitSubscriptionConfigApplySeatIncreaseConfig(TypedDict, total=False): - is_prorated: Required[bool] - """Indicates whether a mid-period seat increase should be prorated.""" - - -class AddRecurringCommitSubscriptionConfig(TypedDict, total=False): - """Attach a subscription to the recurring commit/credit.""" - - apply_seat_increase_config: Required[AddRecurringCommitSubscriptionConfigApplySeatIncreaseConfig] - - subscription_id: Required[str] - """ID of the subscription to configure on the recurring commit/credit.""" - - allocation: Literal["POOLED", "INDIVIDUAL"] - """If set to POOLED, allocation added per seat is pooled across the account. - - If set to INDIVIDUAL, each seat in the subscription will have its own - allocation. - """ - - -class AddRecurringCommit(TypedDict, total=False): - access_amount: Required[AddRecurringCommitAccessAmount] - """The amount of commit to grant.""" - - commit_duration: Required[AddRecurringCommitCommitDuration] - """Defines the length of the access schedule for each created commit/credit. - - The value represents the number of units. Unit defaults to "PERIODS", where the - length of a period is determined by the recurrence_frequency. - """ - - priority: Required[float] - """Will be passed down to the individual commits""" - - product_id: Required[str] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """determines the start time for the first commit""" - - applicable_product_ids: SequenceNotStr[str] - """Will be passed down to the individual commits""" - - applicable_product_tags: SequenceNotStr[str] - """Will be passed down to the individual commits""" - - description: str - """Will be passed down to the individual commits""" - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Determines when the contract will stop creating recurring commits. optional""" - - hierarchy_configuration: CommitHierarchyConfiguration - """Optional configuration for recurring credit hierarchy access control""" - - invoice_amount: AddRecurringCommitInvoiceAmount - """The amount the customer should be billed for the commit. Not required.""" - - name: str - """displayed on invoices. will be passed through to the individual commits""" - - netsuite_sales_order_id: str - """Will be passed down to the individual commits""" - - proration: Literal["NONE", "FIRST", "LAST", "FIRST_AND_LAST"] - """Determines whether the first and last commit will be prorated. - - If not provided, the default is FIRST_AND_LAST (i.e. prorate both the first and - last commits). - """ - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - """Whether the created commits will use the commit rate or list rate""" - - recurrence_frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"] - """The frequency at which the recurring commits will be created. - - If not provided: - The commits will be created on the usage invoice frequency. - If provided: - The period defined in the duration will correspond to this - frequency. - Commits will be created aligned with the recurring commit's - starting_at rather than the usage invoice dates. - """ - - rollover_fraction: float - """Will be passed down to the individual commits. - - This controls how much of an individual unexpired commit will roll over upon - contract transition. Must be between 0 and 1. - """ - - specifiers: Iterable[CommitSpecifierInput] - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - Instead, to target usage by product or product tag, pass those values in the - body of `specifiers`. - """ - - subscription_config: AddRecurringCommitSubscriptionConfig - """Attach a subscription to the recurring commit/credit.""" - - temporary_id: str - """ - A temporary ID that can be used to reference the recurring commit for commit - specific overrides. - """ - - -class AddRecurringCreditAccessAmount(TypedDict, total=False): - """The amount of commit to grant.""" - - credit_type_id: Required[str] - - unit_price: Required[float] - - quantity: float - """ - This field is required unless a subscription is attached via - `subscription_config`. - """ - - -class AddRecurringCreditCommitDuration(TypedDict, total=False): - """Defines the length of the access schedule for each created commit/credit. - - The value represents the number of units. Unit defaults to "PERIODS", where the length of a period is determined by the recurrence_frequency. - """ - - value: Required[float] - - unit: Literal["PERIODS"] - - -class AddRecurringCreditSubscriptionConfigApplySeatIncreaseConfig(TypedDict, total=False): - is_prorated: Required[bool] - """Indicates whether a mid-period seat increase should be prorated.""" - - -class AddRecurringCreditSubscriptionConfig(TypedDict, total=False): - """Attach a subscription to the recurring commit/credit.""" - - apply_seat_increase_config: Required[AddRecurringCreditSubscriptionConfigApplySeatIncreaseConfig] - - subscription_id: Required[str] - """ID of the subscription to configure on the recurring commit/credit.""" - - allocation: Literal["POOLED", "INDIVIDUAL"] - """If set to POOLED, allocation added per seat is pooled across the account. - - If set to INDIVIDUAL, each seat in the subscription will have its own - allocation. - """ - - -class AddRecurringCredit(TypedDict, total=False): - access_amount: Required[AddRecurringCreditAccessAmount] - """The amount of commit to grant.""" - - commit_duration: Required[AddRecurringCreditCommitDuration] - """Defines the length of the access schedule for each created commit/credit. - - The value represents the number of units. Unit defaults to "PERIODS", where the - length of a period is determined by the recurrence_frequency. - """ - - priority: Required[float] - """Will be passed down to the individual commits""" - - product_id: Required[str] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """determines the start time for the first commit""" - - applicable_product_ids: SequenceNotStr[str] - """Will be passed down to the individual commits""" - - applicable_product_tags: SequenceNotStr[str] - """Will be passed down to the individual commits""" - - description: str - """Will be passed down to the individual commits""" - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Determines when the contract will stop creating recurring commits. optional""" - - hierarchy_configuration: CommitHierarchyConfiguration - """Optional configuration for recurring credit hierarchy access control""" - - name: str - """displayed on invoices. will be passed through to the individual commits""" - - netsuite_sales_order_id: str - """Will be passed down to the individual commits""" - - proration: Literal["NONE", "FIRST", "LAST", "FIRST_AND_LAST"] - """Determines whether the first and last commit will be prorated. - - If not provided, the default is FIRST_AND_LAST (i.e. prorate both the first and - last commits). - """ - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - """Whether the created commits will use the commit rate or list rate""" - - recurrence_frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"] - """The frequency at which the recurring commits will be created. - - If not provided: - The commits will be created on the usage invoice frequency. - If provided: - The period defined in the duration will correspond to this - frequency. - Commits will be created aligned with the recurring commit's - starting_at rather than the usage invoice dates. - """ - - rollover_fraction: float - """Will be passed down to the individual commits. - - This controls how much of an individual unexpired commit will roll over upon - contract transition. Must be between 0 and 1. - """ - - specifiers: Iterable[CommitSpecifierInput] - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - Instead, to target usage by product or product tag, pass those values in the - body of `specifiers`. - """ - - subscription_config: AddRecurringCreditSubscriptionConfig - """Attach a subscription to the recurring commit/credit.""" - - temporary_id: str - """ - A temporary ID that can be used to reference the recurring commit for commit - specific overrides. - """ - - -class AddResellerRoyaltyAwsOptions(TypedDict, total=False): - aws_account_number: str - - aws_offer_id: str - - aws_payer_reference_id: str - - -class AddResellerRoyaltyGcpOptions(TypedDict, total=False): - gcp_account_id: str - - gcp_offer_id: str - - -class AddResellerRoyalty(TypedDict, total=False): - reseller_type: Required[Literal["AWS", "AWS_PRO_SERVICE", "GCP", "GCP_PRO_SERVICE"]] - - applicable_product_ids: SequenceNotStr[str] - """Must provide at least one of applicable_product_ids or applicable_product_tags.""" - - applicable_product_tags: SequenceNotStr[str] - """Must provide at least one of applicable_product_ids or applicable_product_tags.""" - - aws_options: AddResellerRoyaltyAwsOptions - - ending_before: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] - """Use null to indicate that the existing end timestamp should be removed.""" - - fraction: float - - gcp_options: AddResellerRoyaltyGcpOptions - - netsuite_reseller_id: str - - reseller_contract_value: float - - starting_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - - -class AddRevenueSystemConfigurationUpdateRevenueSystemConfiguration(TypedDict, total=False): - delivery_method: Literal["direct_to_billing_provider", "aws_sqs", "tackle", "aws_sns"] - - provider: Literal["netsuite"] - """The revenue system provider type.""" - - revenue_system_configuration_id: str - - -class AddRevenueSystemConfigurationUpdateSchedule(TypedDict, total=False): - effective_at: Required[Literal["START_OF_CURRENT_PERIOD"]] - """When the revenue system configuration update will take effect.""" - - -class AddRevenueSystemConfigurationUpdate(TypedDict, total=False): - """Update the revenue system configuration on the contract. - - Currently only supports adding a revenue system configuration to a contract that does not already have one. - """ - - revenue_system_configuration: Required[AddRevenueSystemConfigurationUpdateRevenueSystemConfiguration] - - schedule: Required[AddRevenueSystemConfigurationUpdateSchedule] - - -class AddScheduledChargeScheduleRecurringSchedule(TypedDict, total=False): - """Enter the unit price and quantity for the charge or instead only send the amount. - - If amount is sent, the unit price is assumed to be the amount and quantity is inferred to be 1. - """ - - amount_distribution: Required[Literal["DIVIDED", "DIVIDED_ROUNDED", "EACH"]] - - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (exclusive).""" - - frequency: Required[Literal["MONTHLY", "QUARTERLY", "SEMI_ANNUAL", "ANNUAL", "WEEKLY"]] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """RFC 3339 timestamp (inclusive).""" - - amount: float - """Amount for the charge. - - Can be provided instead of unit_price and quantity. If amount is sent, the - unit_price is assumed to be the amount and quantity is inferred to be 1. - """ - - quantity: float - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount and must be specified - with unit_price. If specified amount cannot be provided. - """ - - unit_price: float - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified - with quantity. If specified amount cannot be provided. - """ - - -class AddScheduledChargeScheduleScheduleItem(TypedDict, total=False): - timestamp: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """timestamp of the scheduled event""" - - amount: float - """Amount for the charge. - - Can be provided instead of unit_price and quantity. If amount is sent, the - unit_price is assumed to be the amount and quantity is inferred to be 1. - """ - - quantity: float - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount and must be specified - with unit_price. If specified amount cannot be provided. - """ - - unit_price: float - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified - with quantity. If specified amount cannot be provided. - """ - - -class AddScheduledChargeSchedule(TypedDict, total=False): - """Must provide either schedule_items or recurring_schedule.""" - - credit_type_id: str - """Defaults to USD (cents) if not passed.""" - - do_not_invoice: bool - """This field is only applicable to commit invoice schedules. - - If true, this schedule will not generate an invoice. - """ - - recurring_schedule: AddScheduledChargeScheduleRecurringSchedule - """Enter the unit price and quantity for the charge or instead only send the - amount. - - If amount is sent, the unit price is assumed to be the amount and quantity is - inferred to be 1. - """ - - schedule_items: Iterable[AddScheduledChargeScheduleScheduleItem] - """Either provide amount or provide both unit_price and quantity.""" - - -class AddScheduledCharge(TypedDict, total=False): - product_id: Required[str] - - schedule: Required[AddScheduledChargeSchedule] - """Must provide either schedule_items or recurring_schedule.""" - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - name: str - """displayed on invoices""" - - netsuite_sales_order_id: str - """This field's availability is dependent on your client's configuration.""" - - -class AddSubscriptionProration(TypedDict, total=False): - invoice_behavior: Literal["BILL_IMMEDIATELY", "BILL_ON_NEXT_COLLECTION_DATE"] - """Indicates how mid-period quantity adjustments are invoiced. - - **BILL_IMMEDIATELY**: Only available when collection schedule is `ADVANCE`. The - quantity increase will be billed immediately on the scheduled date. - **BILL_ON_NEXT_COLLECTION_DATE**: The quantity increase will be billed for - in-arrears at the end of the period. - """ - - is_prorated: bool - """Indicates if the partial period will be prorated or charged a full amount.""" - - -class AddSubscriptionSubscriptionRate(TypedDict, total=False): - billing_frequency: Required[Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"]] - """Frequency to bill subscription with. - - Together with product_id, must match existing rate on the rate card. - """ - - product_id: Required[str] - """Must be subscription type product""" - - -class AddSubscriptionSeatConfig(TypedDict, total=False): - initial_seat_ids: Required[SequenceNotStr[str]] - """The initial assigned seats on this subscription.""" - - seat_group_key: Required[str] - """ - The property name, sent on usage events, that identifies the seat ID associated - with the usage event. For example, the property name might be seat_id or - user_id. The property must be set as a group key on billable metrics and a - presentation/pricing group key on contract products. This allows linked - recurring credits with an allocation per seat to be consumed by only one seat's - usage. - """ - - initial_unassigned_seats: float - """The initial amount of unassigned seats on this subscription.""" - - -class AddSubscription(TypedDict, total=False): - collection_schedule: Required[Literal["ADVANCE", "ARREARS"]] - - proration: Required[AddSubscriptionProration] - - subscription_rate: Required[AddSubscriptionSubscriptionRate] - - custom_fields: Dict[str, str] - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - description: str - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Exclusive end time for the subscription. - - If not provided, subscription inherits contract end date. - """ - - initial_quantity: float - """The initial quantity for the subscription. - - It must be non-negative value. Required if quantity_management_mode is - QUANTITY_ONLY. - """ - - name: str - - quantity_management_mode: Literal["SEAT_BASED", "QUANTITY_ONLY"] - """Determines how the subscription's quantity is controlled. - - Defaults to QUANTITY_ONLY. **QUANTITY_ONLY**: The subscription quantity is - specified directly on the subscription. `initial_quantity` must be provided with - this option. Compatible with recurring commits/credits that use POOLED - allocation. **SEAT_BASED**: Use when you want to pass specific seat identifiers - (e.g. add user_123) to increment and decrement a subscription quantity, rather - than directly providing the quantity. You must use a **SEAT_BASED** subscription - to use a linked recurring credit with an allocation per seat. `seat_config` must - be provided with this option. - """ - - seat_config: AddSubscriptionSeatConfig - - starting_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Inclusive start time for the subscription. - - If not provided, defaults to contract start date - """ - - temporary_id: str - """ - A temporary ID used to reference the subscription in recurring commit/credit - subscription configs created within the same payload. - """ - - -class ArchiveCommit(TypedDict, total=False): - id: Required[str] - - -class ArchiveCredit(TypedDict, total=False): - id: Required[str] - - -class ArchiveScheduledCharge(TypedDict, total=False): - id: Required[str] - - -class RemoveOverride(TypedDict, total=False): - id: Required[str] - - -class UpdateCommitAccessScheduleAddScheduleItem(TypedDict, total=False): - amount: Required[float] - - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - -class UpdateCommitAccessScheduleRemoveScheduleItem(TypedDict, total=False): - id: Required[str] - - -class UpdateCommitAccessScheduleUpdateScheduleItem(TypedDict, total=False): - id: Required[str] - - amount: float - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - - starting_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - - -class UpdateCommitAccessSchedule(TypedDict, total=False): - add_schedule_items: Iterable[UpdateCommitAccessScheduleAddScheduleItem] - - remove_schedule_items: Iterable[UpdateCommitAccessScheduleRemoveScheduleItem] - - update_schedule_items: Iterable[UpdateCommitAccessScheduleUpdateScheduleItem] - - -class UpdateCommitInvoiceScheduleAddScheduleItem(TypedDict, total=False): - timestamp: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - amount: float - - quantity: float - - unit_price: float - - -class UpdateCommitInvoiceScheduleRemoveScheduleItem(TypedDict, total=False): - id: Required[str] - - -class UpdateCommitInvoiceScheduleUpdateScheduleItem(TypedDict, total=False): - id: Required[str] - - amount: float - - quantity: float - - timestamp: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - - unit_price: float - - -class UpdateCommitInvoiceSchedule(TypedDict, total=False): - add_schedule_items: Iterable[UpdateCommitInvoiceScheduleAddScheduleItem] - - remove_schedule_items: Iterable[UpdateCommitInvoiceScheduleRemoveScheduleItem] - - update_schedule_items: Iterable[UpdateCommitInvoiceScheduleUpdateScheduleItem] - - -class UpdateCommit(TypedDict, total=False): - commit_id: Required[str] - - access_schedule: UpdateCommitAccessSchedule - - applicable_product_ids: Optional[SequenceNotStr[str]] - """Which products the commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - applicable_product_tags: Optional[SequenceNotStr[str]] - """Which tags the commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - description: str - - hierarchy_configuration: CommitHierarchyConfiguration - """Optional configuration for commit hierarchy access control""" - - invoice_schedule: UpdateCommitInvoiceSchedule - - name: str - - netsuite_sales_order_id: Optional[str] - - priority: Optional[float] - - product_id: str - - rate_type: Literal["LIST_RATE", "COMMIT_RATE"] - """ - If provided, updates the commit to use the specified rate type for current and - future invoices. Previously finalized invoices will need to be voided and - regenerated to reflect the rate type change. - """ - - rollover_fraction: Optional[float] - - -class UpdateCreditAccessScheduleAddScheduleItem(TypedDict, total=False): - amount: Required[float] - - ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - -class UpdateCreditAccessScheduleRemoveScheduleItem(TypedDict, total=False): - id: Required[str] - - -class UpdateCreditAccessScheduleUpdateScheduleItem(TypedDict, total=False): - id: Required[str] - - amount: float - - ending_before: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - - starting_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - - -class UpdateCreditAccessSchedule(TypedDict, total=False): - add_schedule_items: Iterable[UpdateCreditAccessScheduleAddScheduleItem] - - remove_schedule_items: Iterable[UpdateCreditAccessScheduleRemoveScheduleItem] - - update_schedule_items: Iterable[UpdateCreditAccessScheduleUpdateScheduleItem] - - -class UpdateCredit(TypedDict, total=False): - credit_id: Required[str] - - access_schedule: UpdateCreditAccessSchedule - - applicable_product_ids: Optional[SequenceNotStr[str]] - """Which products the commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - applicable_product_tags: Optional[SequenceNotStr[str]] - """Which tags the commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - description: str - - hierarchy_configuration: CommitHierarchyConfiguration - """Optional configuration for commit hierarchy access control""" - - name: str - - netsuite_sales_order_id: Optional[str] - - priority: Optional[float] - - product_id: str - - rate_type: Literal["LIST_RATE", "COMMIT_RATE"] - """ - If provided, updates the credit to use the specified rate type for current and - future invoices. Previously finalized invoices will need to be voided and - regenerated to reflect the rate type change. - """ - - rollover_fraction: Optional[float] - - -class UpdatePrepaidBalanceThresholdConfigurationCommit(UpdateBaseThresholdCommit, total=False): - applicable_product_ids: Optional[SequenceNotStr[str]] - """Which products the threshold commit applies to. - - If both applicable_product_ids and applicable_product_tags are not provided, the - commit applies to all products. - """ - - applicable_product_tags: Optional[SequenceNotStr[str]] - """Which tags the threshold commit applies to. - - If both applicable_product_ids and applicable_product_tags are not provided, the - commit applies to all products. - """ - - specifiers: Optional[Iterable[CommitSpecifierInput]] - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - Instead, to target usage by product or product tag, pass those values in the - body of `specifiers`. - """ - - -class UpdatePrepaidBalanceThresholdConfiguration(TypedDict, total=False): - commit: UpdatePrepaidBalanceThresholdConfigurationCommit - - custom_credit_type_id: Optional[str] - """ - If provided, the threshold, recharge-to amount, and the resulting threshold - commit amount will be in terms of this credit type instead of the fiat currency. - """ - - is_enabled: bool - """ - When set to false, the contract will not be evaluated against the - threshold_amount. Toggling to true will result an immediate evaluation, - regardless of prior state. - """ - - payment_gate_config: PaymentGateConfigV2 - - recharge_to_amount: float - """Specify the amount the balance should be recharged to.""" - - threshold_amount: float - """Specify the threshold amount for the contract. - - Each time the contract's balance lowers to this amount, a threshold charge will - be initiated. - """ - - -class UpdateRecurringCommitAccessAmount(TypedDict, total=False): - quantity: float - - unit_price: float - - -class UpdateRecurringCommitInvoiceAmount(TypedDict, total=False): - quantity: float - - unit_price: float - - -class UpdateRecurringCommit(TypedDict, total=False): - recurring_commit_id: Required[str] - - access_amount: UpdateRecurringCommitAccessAmount - - ending_before: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] - - invoice_amount: UpdateRecurringCommitInvoiceAmount - - rate_type: Literal["LIST_RATE", "COMMIT_RATE"] - """ - If provided, updates the recurring commit to use the specified rate type when - generating future commits. - """ - - -class UpdateRecurringCreditAccessAmount(TypedDict, total=False): - quantity: float - - unit_price: float - - -class UpdateRecurringCredit(TypedDict, total=False): - recurring_credit_id: Required[str] - - access_amount: UpdateRecurringCreditAccessAmount - - ending_before: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] - - rate_type: Literal["LIST_RATE", "COMMIT_RATE"] - """ - If provided, updates the recurring credit to use the specified rate type when - generating future credits. - """ - - -class UpdateScheduledChargeInvoiceScheduleAddScheduleItem(TypedDict, total=False): - timestamp: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - amount: float - - quantity: float - - unit_price: float - - -class UpdateScheduledChargeInvoiceScheduleRemoveScheduleItem(TypedDict, total=False): - id: Required[str] - - -class UpdateScheduledChargeInvoiceScheduleUpdateScheduleItem(TypedDict, total=False): - id: Required[str] - - amount: float - - quantity: float - - timestamp: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - - unit_price: float - - -class UpdateScheduledChargeInvoiceSchedule(TypedDict, total=False): - add_schedule_items: Iterable[UpdateScheduledChargeInvoiceScheduleAddScheduleItem] - - remove_schedule_items: Iterable[UpdateScheduledChargeInvoiceScheduleRemoveScheduleItem] - - update_schedule_items: Iterable[UpdateScheduledChargeInvoiceScheduleUpdateScheduleItem] - - -class UpdateScheduledCharge(TypedDict, total=False): - scheduled_charge_id: Required[str] - - invoice_schedule: UpdateScheduledChargeInvoiceSchedule - - netsuite_sales_order_id: Optional[str] - - -class UpdateSpendThresholdConfiguration(TypedDict, total=False): - commit: UpdateBaseThresholdCommit - - is_enabled: bool - """ - When set to false, the contract will not be evaluated against the - threshold_amount. Toggling to true will result an immediate evaluation, - regardless of prior state. - """ - - payment_gate_config: PaymentGateConfigV2 - - threshold_amount: float - """Specify the threshold amount for the contract. - - Each time the contract's usage hits this amount, a threshold charge will be - initiated. - """ - - -class UpdateSubscriptionQuantityManagementModeUpdateSeatConfig(TypedDict, total=False): - seat_group_key: Required[str] - - -class UpdateSubscriptionQuantityManagementModeUpdate(TypedDict, total=False): - """ - Update the subscription's quantity management mode from QUANTITY_ONLY to SEAT_BASED with the provided seat_group_key. - """ - - quantity_management_mode: Required[Literal["SEAT_BASED"]] - - seat_config: Required[UpdateSubscriptionQuantityManagementModeUpdateSeatConfig] - - -class UpdateSubscriptionQuantityUpdate(TypedDict, total=False): - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - - quantity: float - """The new quantity for the subscription. - - Must be provided if quantity_delta is not provided. Must be non-negative. - """ - - quantity_delta: float - """The delta to add to the subscription's quantity. - - Must be provided if quantity is not provided. Can't be zero. It also can't - result in a negative quantity on the subscription. - """ - - -class UpdateSubscriptionSeatUpdatesAddSeatID(TypedDict, total=False): - seat_ids: Required[SequenceNotStr[str]] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """Assigned seats will be added/removed starting at this date.""" - - -class UpdateSubscriptionSeatUpdatesAddUnassignedSeat(TypedDict, total=False): - quantity: Required[float] - """ - The number of unassigned seats on the subscription will increase/decrease by - this delta. Must be greater than 0. - """ - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """Unassigned seats will be updated starting at this date.""" - - -class UpdateSubscriptionSeatUpdatesRemoveSeatID(TypedDict, total=False): - seat_ids: Required[SequenceNotStr[str]] - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """Assigned seats will be added/removed starting at this date.""" - - -class UpdateSubscriptionSeatUpdatesRemoveUnassignedSeat(TypedDict, total=False): - quantity: Required[float] - """ - The number of unassigned seats on the subscription will increase/decrease by - this delta. Must be greater than 0. - """ - - starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] - """Unassigned seats will be updated starting at this date.""" - - -class UpdateSubscriptionSeatUpdates(TypedDict, total=False): - add_seat_ids: Iterable[UpdateSubscriptionSeatUpdatesAddSeatID] - """Adds seat IDs to the subscription. - - If there are unassigned seats, the new seat IDs will fill these unassigned seats - and not increase the total subscription quantity. Otherwise, if there are more - new seat IDs than unassigned seats, the total subscription quantity will - increase. - """ - - add_unassigned_seats: Iterable[UpdateSubscriptionSeatUpdatesAddUnassignedSeat] - """Adds unassigned seats to the subscription. - - This will increase the total subscription quantity. - """ - - remove_seat_ids: Iterable[UpdateSubscriptionSeatUpdatesRemoveSeatID] - """Removes seat IDs from the subscription, if possible. - - If a seat ID is removed, the total subscription quantity will decrease. - Otherwise, if the seat ID is not found on the subscription, this is a no-op. - """ - - remove_unassigned_seats: Iterable[UpdateSubscriptionSeatUpdatesRemoveUnassignedSeat] - """Removes unassigned seats from the subscription. - - This will decrease the total subscription quantity if there are are unassigned - seats. - """ - - -class UpdateSubscription(TypedDict, total=False): - subscription_id: Required[str] - - ending_before: Annotated[Union[str, datetime, None], PropertyInfo(format="iso8601")] - - quantity_management_mode_update: UpdateSubscriptionQuantityManagementModeUpdate - """ - Update the subscription's quantity management mode from QUANTITY_ONLY to - SEAT_BASED with the provided seat_group_key. - """ - - quantity_updates: Iterable[UpdateSubscriptionQuantityUpdate] - """ - Quantity changes are applied on the effective date based on the order which they - are sent. For example, if I scheduled the quantity to be 12 on May 21 and then - scheduled a quantity delta change of -1, the result from that day would be 11. - """ - - seat_updates: UpdateSubscriptionSeatUpdates diff --git a/src/metronome/types/v2/contract_edit_response.py b/src/metronome/types/v2/contract_edit_response.py deleted file mode 100644 index c6d671161..000000000 --- a/src/metronome/types/v2/contract_edit_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel -from ..shared.id import ID - -__all__ = ["ContractEditResponse"] - - -class ContractEditResponse(BaseModel): - data: ID diff --git a/src/metronome/types/v2/contract_get_edit_history_params.py b/src/metronome/types/v2/contract_get_edit_history_params.py deleted file mode 100644 index 7d992b21d..000000000 --- a/src/metronome/types/v2/contract_get_edit_history_params.py +++ /dev/null @@ -1,13 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing_extensions import Required, TypedDict - -__all__ = ["ContractGetEditHistoryParams"] - - -class ContractGetEditHistoryParams(TypedDict, total=False): - contract_id: Required[str] - - customer_id: Required[str] diff --git a/src/metronome/types/v2/contract_get_edit_history_response.py b/src/metronome/types/v2/contract_get_edit_history_response.py deleted file mode 100644 index 90ee55ee6..000000000 --- a/src/metronome/types/v2/contract_get_edit_history_response.py +++ /dev/null @@ -1,1239 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import Dict, List, Optional -from datetime import datetime -from typing_extensions import Literal - -from ..._models import BaseModel -from ..shared.tier import Tier -from ..shared.discount import Discount -from ..shared.pro_service import ProService -from ..shared.subscription import Subscription -from ..shared.override_tier import OverrideTier -from ..shared.commit_specifier import CommitSpecifier -from ..shared.credit_type_data import CreditTypeData -from ..shared.schedule_duration import ScheduleDuration -from ..shared.commit_specifier_input import CommitSpecifierInput -from ..shared.payment_gate_config_v2 import PaymentGateConfigV2 -from ..shared.schedule_point_in_time import SchedulePointInTime -from ..shared.update_base_threshold_commit import UpdateBaseThresholdCommit -from ..shared.commit_hierarchy_configuration import CommitHierarchyConfiguration -from ..shared.spend_threshold_configuration_v2 import SpendThresholdConfigurationV2 -from ..shared.recurring_commit_subscription_config import RecurringCommitSubscriptionConfig -from ..shared.prepaid_balance_threshold_configuration_v2 import PrepaidBalanceThresholdConfigurationV2 - -__all__ = [ - "ContractGetEditHistoryResponse", - "Data", - "DataAddCommit", - "DataAddCommitProduct", - "DataAddCommitInvoiceSchedule", - "DataAddCommitInvoiceScheduleScheduleItem", - "DataAddCredit", - "DataAddCreditProduct", - "DataAddOverride", - "DataAddOverrideOverrideSpecifier", - "DataAddOverrideOverwriteRate", - "DataAddOverrideProduct", - "DataAddRecurringCommit", - "DataAddRecurringCommitAccessAmount", - "DataAddRecurringCommitCommitDuration", - "DataAddRecurringCommitProduct", - "DataAddRecurringCommitContract", - "DataAddRecurringCommitInvoiceAmount", - "DataAddRecurringCredit", - "DataAddRecurringCreditAccessAmount", - "DataAddRecurringCreditCommitDuration", - "DataAddRecurringCreditProduct", - "DataAddRecurringCreditContract", - "DataAddResellerRoyalty", - "DataAddScheduledCharge", - "DataAddScheduledChargeProduct", - "DataAddUsageFilter", - "DataArchiveCommit", - "DataArchiveCredit", - "DataArchiveScheduledCharge", - "DataRemoveOverride", - "DataUpdateCommit", - "DataUpdateCommitAccessSchedule", - "DataUpdateCommitAccessScheduleAddScheduleItem", - "DataUpdateCommitAccessScheduleRemoveScheduleItem", - "DataUpdateCommitAccessScheduleUpdateScheduleItem", - "DataUpdateCommitInvoiceSchedule", - "DataUpdateCommitInvoiceScheduleAddScheduleItem", - "DataUpdateCommitInvoiceScheduleRemoveScheduleItem", - "DataUpdateCommitInvoiceScheduleUpdateScheduleItem", - "DataUpdateCredit", - "DataUpdateCreditAccessSchedule", - "DataUpdateCreditAccessScheduleAddScheduleItem", - "DataUpdateCreditAccessScheduleRemoveScheduleItem", - "DataUpdateCreditAccessScheduleUpdateScheduleItem", - "DataUpdateDiscount", - "DataUpdateDiscountSchedule", - "DataUpdateDiscountScheduleRecurringSchedule", - "DataUpdateDiscountScheduleScheduleItem", - "DataUpdatePrepaidBalanceThresholdConfiguration", - "DataUpdatePrepaidBalanceThresholdConfigurationCommit", - "DataUpdateRecurringCommit", - "DataUpdateRecurringCommitAccessAmount", - "DataUpdateRecurringCommitInvoiceAmount", - "DataUpdateRecurringCredit", - "DataUpdateRecurringCreditAccessAmount", - "DataUpdateRefundInvoice", - "DataUpdateScheduledCharge", - "DataUpdateScheduledChargeInvoiceSchedule", - "DataUpdateScheduledChargeInvoiceScheduleAddScheduleItem", - "DataUpdateScheduledChargeInvoiceScheduleRemoveScheduleItem", - "DataUpdateScheduledChargeInvoiceScheduleUpdateScheduleItem", - "DataUpdateSpendThresholdConfiguration", - "DataUpdateSubscription", - "DataUpdateSubscriptionQuantityUpdate", - "DataUpdateSubscriptionSeatUpdates", - "DataUpdateSubscriptionSeatUpdatesAddSeatID", - "DataUpdateSubscriptionSeatUpdatesAddUnassignedSeat", - "DataUpdateSubscriptionSeatUpdatesRemoveSeatID", - "DataUpdateSubscriptionSeatUpdatesRemoveUnassignedSeat", -] - - -class DataAddCommitProduct(BaseModel): - id: str - - name: str - - -class DataAddCommitInvoiceScheduleScheduleItem(BaseModel): - id: str - - timestamp: datetime - - amount: Optional[float] = None - - invoice_id: Optional[str] = None - - quantity: Optional[float] = None - - unit_price: Optional[float] = None - - -class DataAddCommitInvoiceSchedule(BaseModel): - """The schedule that the customer will be invoiced for this commit.""" - - credit_type: Optional[CreditTypeData] = None - - do_not_invoice: Optional[bool] = None - """If true, this schedule will not generate an invoice.""" - - schedule_items: Optional[List[DataAddCommitInvoiceScheduleScheduleItem]] = None - - -class DataAddCommit(BaseModel): - id: str - - product: DataAddCommitProduct - - type: Literal["PREPAID", "POSTPAID"] - - access_schedule: Optional[ScheduleDuration] = None - """ - The schedule that the customer will gain access to the credits purposed with - this commit. - """ - - applicable_product_ids: Optional[List[str]] = None - - applicable_product_tags: Optional[List[str]] = None - - description: Optional[str] = None - - hierarchy_configuration: Optional[CommitHierarchyConfiguration] = None - """Optional configuration for commit hierarchy access control""" - - invoice_schedule: Optional[DataAddCommitInvoiceSchedule] = None - """The schedule that the customer will be invoiced for this commit.""" - - name: Optional[str] = None - - netsuite_sales_order_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - priority: Optional[float] = None - """ - If multiple credits or commits are applicable, the one with the lower priority - will apply first. - """ - - rate_type: Optional[Literal["COMMIT_RATE", "LIST_RATE"]] = None - - rollover_fraction: Optional[float] = None - - salesforce_opportunity_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - specifiers: Optional[List[CommitSpecifierInput]] = None - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - Instead, to target usage by product or product tag, pass those values in the - body of `specifiers`. - """ - - -class DataAddCreditProduct(BaseModel): - id: str - - name: str - - -class DataAddCredit(BaseModel): - id: str - - product: DataAddCreditProduct - - type: Literal["CREDIT"] - - access_schedule: Optional[ScheduleDuration] = None - """The schedule that the customer will gain access to the credits.""" - - applicable_product_ids: Optional[List[str]] = None - - applicable_product_tags: Optional[List[str]] = None - - description: Optional[str] = None - - hierarchy_configuration: Optional[CommitHierarchyConfiguration] = None - """Optional configuration for recurring credit hierarchy access control""" - - name: Optional[str] = None - - netsuite_sales_order_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - priority: Optional[float] = None - """ - If multiple credits or commits are applicable, the one with the lower priority - will apply first. - """ - - salesforce_opportunity_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - specifiers: Optional[List[CommitSpecifierInput]] = None - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - Instead, to target usage by product or product tag, pass those values in the - body of `specifiers`. - """ - - -class DataAddOverrideOverrideSpecifier(BaseModel): - billing_frequency: Optional[Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"]] = None - - commit_ids: Optional[List[str]] = None - - presentation_group_values: Optional[Dict[str, Optional[str]]] = None - - pricing_group_values: Optional[Dict[str, str]] = None - - product_id: Optional[str] = None - - product_tags: Optional[List[str]] = None - - recurring_commit_ids: Optional[List[str]] = None - - recurring_credit_ids: Optional[List[str]] = None - - -class DataAddOverrideOverwriteRate(BaseModel): - rate_type: Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "TIERED", "TIERED_PERCENTAGE", "CUSTOM"] - - credit_type: Optional[CreditTypeData] = None - - custom_rate: Optional[Dict[str, object]] = None - """Only set for CUSTOM rate_type. - - This field is interpreted by custom rate processors. - """ - - is_prorated: Optional[bool] = None - """Default proration configuration. - - Only valid for SUBSCRIPTION rate_type. Must be set to true. - """ - - price: Optional[float] = None - """Default price. - - For FLAT rate_type, this must be >=0. For PERCENTAGE rate_type, this is a - decimal fraction, e.g. use 0.1 for 10%; this must be >=0 and <=1. - """ - - quantity: Optional[float] = None - """Default quantity. For SUBSCRIPTION rate_type, this must be >=0.""" - - tiers: Optional[List[Tier]] = None - """Only set for TIERED rate_type.""" - - -class DataAddOverrideProduct(BaseModel): - id: str - - name: str - - -class DataAddOverride(BaseModel): - id: str - - starting_at: datetime - - applicable_product_tags: Optional[List[str]] = None - - ending_before: Optional[datetime] = None - - entitled: Optional[bool] = None - - is_commit_specific: Optional[bool] = None - - multiplier: Optional[float] = None - - override_specifiers: Optional[List[DataAddOverrideOverrideSpecifier]] = None - - override_tiers: Optional[List[OverrideTier]] = None - - overwrite_rate: Optional[DataAddOverrideOverwriteRate] = None - - priority: Optional[float] = None - - product: Optional[DataAddOverrideProduct] = None - - target: Optional[Literal["COMMIT_RATE", "LIST_RATE"]] = None - - type: Optional[Literal["OVERWRITE", "MULTIPLIER", "TIERED"]] = None - - -class DataAddRecurringCommitAccessAmount(BaseModel): - """The amount of commit to grant.""" - - credit_type_id: str - - unit_price: float - - quantity: Optional[float] = None - - -class DataAddRecurringCommitCommitDuration(BaseModel): - """The amount of time the created commits will be valid for""" - - value: float - - unit: Optional[Literal["PERIODS"]] = None - - -class DataAddRecurringCommitProduct(BaseModel): - id: str - - name: str - - -class DataAddRecurringCommitContract(BaseModel): - id: str - - -class DataAddRecurringCommitInvoiceAmount(BaseModel): - """The amount the customer should be billed for the commit. Not required.""" - - credit_type_id: str - - quantity: float - - unit_price: float - - -class DataAddRecurringCommit(BaseModel): - id: str - - access_amount: DataAddRecurringCommitAccessAmount - """The amount of commit to grant.""" - - commit_duration: DataAddRecurringCommitCommitDuration - """The amount of time the created commits will be valid for""" - - priority: float - """Will be passed down to the individual commits""" - - product: DataAddRecurringCommitProduct - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - """Whether the created commits will use the commit rate or list rate""" - - starting_at: datetime - """Determines the start time for the first commit""" - - applicable_product_ids: Optional[List[str]] = None - """Will be passed down to the individual commits""" - - applicable_product_tags: Optional[List[str]] = None - """Will be passed down to the individual commits""" - - contract: Optional[DataAddRecurringCommitContract] = None - - description: Optional[str] = None - """Will be passed down to the individual commits""" - - ending_before: Optional[datetime] = None - """Determines when the contract will stop creating recurring commits. Optional""" - - hierarchy_configuration: Optional[CommitHierarchyConfiguration] = None - """Optional configuration for recurring credit hierarchy access control""" - - invoice_amount: Optional[DataAddRecurringCommitInvoiceAmount] = None - """The amount the customer should be billed for the commit. Not required.""" - - name: Optional[str] = None - """Displayed on invoices. Will be passed through to the individual commits""" - - netsuite_sales_order_id: Optional[str] = None - """Will be passed down to the individual commits""" - - proration: Optional[Literal["NONE", "FIRST", "LAST", "FIRST_AND_LAST"]] = None - """Determines whether the first and last commit will be prorated. - - If not provided, the default is FIRST_AND_LAST (i.e. prorate both the first and - last commits). - """ - - recurrence_frequency: Optional[Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"]] = None - """The frequency at which the recurring commits will be created. - - If not provided: - The commits will be created on the usage invoice frequency. - If provided: - The period defined in the duration will correspond to this - frequency. - Commits will be created aligned with the recurring commit's - starting_at rather than the usage invoice dates. - """ - - rollover_fraction: Optional[float] = None - """Will be passed down to the individual commits. - - This controls how much of an individual unexpired commit will roll over upon - contract transition. Must be between 0 and 1. - """ - - specifiers: Optional[List[CommitSpecifier]] = None - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. - """ - - subscription_config: Optional[RecurringCommitSubscriptionConfig] = None - """Attach a subscription to the recurring commit/credit.""" - - -class DataAddRecurringCreditAccessAmount(BaseModel): - """The amount of commit to grant.""" - - credit_type_id: str - - unit_price: float - - quantity: Optional[float] = None - - -class DataAddRecurringCreditCommitDuration(BaseModel): - """The amount of time the created commits will be valid for""" - - value: float - - unit: Optional[Literal["PERIODS"]] = None - - -class DataAddRecurringCreditProduct(BaseModel): - id: str - - name: str - - -class DataAddRecurringCreditContract(BaseModel): - id: str - - -class DataAddRecurringCredit(BaseModel): - id: str - - access_amount: DataAddRecurringCreditAccessAmount - """The amount of commit to grant.""" - - commit_duration: DataAddRecurringCreditCommitDuration - """The amount of time the created commits will be valid for""" - - priority: float - """Will be passed down to the individual commits""" - - product: DataAddRecurringCreditProduct - - rate_type: Literal["COMMIT_RATE", "LIST_RATE"] - """Whether the created commits will use the commit rate or list rate""" - - starting_at: datetime - """Determines the start time for the first commit""" - - applicable_product_ids: Optional[List[str]] = None - """Will be passed down to the individual commits""" - - applicable_product_tags: Optional[List[str]] = None - """Will be passed down to the individual commits""" - - contract: Optional[DataAddRecurringCreditContract] = None - - description: Optional[str] = None - """Will be passed down to the individual commits""" - - ending_before: Optional[datetime] = None - """Determines when the contract will stop creating recurring commits. Optional""" - - hierarchy_configuration: Optional[CommitHierarchyConfiguration] = None - """Optional configuration for recurring credit hierarchy access control""" - - name: Optional[str] = None - """Displayed on invoices. Will be passed through to the individual commits""" - - netsuite_sales_order_id: Optional[str] = None - """Will be passed down to the individual commits""" - - proration: Optional[Literal["NONE", "FIRST", "LAST", "FIRST_AND_LAST"]] = None - """Determines whether the first and last commit will be prorated. - - If not provided, the default is FIRST_AND_LAST (i.e. prorate both the first and - last commits). - """ - - recurrence_frequency: Optional[Literal["MONTHLY", "QUARTERLY", "ANNUAL", "WEEKLY"]] = None - """The frequency at which the recurring commits will be created. - - If not provided: - The commits will be created on the usage invoice frequency. - If provided: - The period defined in the duration will correspond to this - frequency. - Commits will be created aligned with the recurring commit's - starting_at rather than the usage invoice dates. - """ - - rollover_fraction: Optional[float] = None - """Will be passed down to the individual commits. - - This controls how much of an individual unexpired commit will roll over upon - contract transition. Must be between 0 and 1. - """ - - specifiers: Optional[List[CommitSpecifier]] = None - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. - """ - - subscription_config: Optional[RecurringCommitSubscriptionConfig] = None - """Attach a subscription to the recurring commit/credit.""" - - -class DataAddResellerRoyalty(BaseModel): - reseller_type: Literal["AWS", "AWS_PRO_SERVICE", "GCP", "GCP_PRO_SERVICE"] - - applicable_product_ids: Optional[List[str]] = None - - applicable_product_tags: Optional[List[str]] = None - - aws_account_number: Optional[str] = None - - aws_offer_id: Optional[str] = None - - aws_payer_reference_id: Optional[str] = None - - ending_before: Optional[datetime] = None - - fraction: Optional[float] = None - - gcp_account_id: Optional[str] = None - - gcp_offer_id: Optional[str] = None - - netsuite_reseller_id: Optional[str] = None - - reseller_contract_value: Optional[float] = None - - starting_at: Optional[datetime] = None - - -class DataAddScheduledChargeProduct(BaseModel): - id: str - - name: str - - -class DataAddScheduledCharge(BaseModel): - id: str - - product: DataAddScheduledChargeProduct - - schedule: SchedulePointInTime - - name: Optional[str] = None - """displayed on invoices""" - - netsuite_sales_order_id: Optional[str] = None - """This field's availability is dependent on your client's configuration.""" - - -class DataAddUsageFilter(BaseModel): - group_key: str - - group_values: List[str] - - starting_at: datetime - """ - This will match contract starting_at value if usage filter is active from the - beginning of the contract. - """ - - ending_before: Optional[datetime] = None - """ - This will match contract ending_before value if usage filter is active until the - end of the contract. It will be undefined if the contract is open-ended. - """ - - -class DataArchiveCommit(BaseModel): - id: str - - -class DataArchiveCredit(BaseModel): - id: str - - -class DataArchiveScheduledCharge(BaseModel): - id: str - - -class DataRemoveOverride(BaseModel): - id: str - - -class DataUpdateCommitAccessScheduleAddScheduleItem(BaseModel): - amount: float - - ending_before: datetime - """RFC 3339 timestamp (exclusive)""" - - starting_at: datetime - """RFC 3339 timestamp (inclusive)""" - - -class DataUpdateCommitAccessScheduleRemoveScheduleItem(BaseModel): - id: str - - -class DataUpdateCommitAccessScheduleUpdateScheduleItem(BaseModel): - id: str - - amount: Optional[float] = None - - ending_before: Optional[datetime] = None - """RFC 3339 timestamp (exclusive)""" - - starting_at: Optional[datetime] = None - """RFC 3339 timestamp (inclusive)""" - - -class DataUpdateCommitAccessSchedule(BaseModel): - add_schedule_items: Optional[List[DataUpdateCommitAccessScheduleAddScheduleItem]] = None - - remove_schedule_items: Optional[List[DataUpdateCommitAccessScheduleRemoveScheduleItem]] = None - - update_schedule_items: Optional[List[DataUpdateCommitAccessScheduleUpdateScheduleItem]] = None - - -class DataUpdateCommitInvoiceScheduleAddScheduleItem(BaseModel): - timestamp: datetime - - amount: Optional[float] = None - - quantity: Optional[float] = None - - unit_price: Optional[float] = None - - -class DataUpdateCommitInvoiceScheduleRemoveScheduleItem(BaseModel): - id: str - - -class DataUpdateCommitInvoiceScheduleUpdateScheduleItem(BaseModel): - id: str - - amount: Optional[float] = None - - quantity: Optional[float] = None - - timestamp: Optional[datetime] = None - - unit_price: Optional[float] = None - - -class DataUpdateCommitInvoiceSchedule(BaseModel): - add_schedule_items: Optional[List[DataUpdateCommitInvoiceScheduleAddScheduleItem]] = None - - remove_schedule_items: Optional[List[DataUpdateCommitInvoiceScheduleRemoveScheduleItem]] = None - - update_schedule_items: Optional[List[DataUpdateCommitInvoiceScheduleUpdateScheduleItem]] = None - - -class DataUpdateCommit(BaseModel): - id: str - - access_schedule: Optional[DataUpdateCommitAccessSchedule] = None - - applicable_product_ids: Optional[List[str]] = None - """Which products the commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - applicable_product_tags: Optional[List[str]] = None - """Which tags the commit applies to. - - If applicable_product_ids, applicable_product_tags or specifiers are not - provided, the commit applies to all products. - """ - - description: Optional[str] = None - - hierarchy_configuration: Optional[CommitHierarchyConfiguration] = None - """Optional configuration for commit hierarchy access control""" - - invoice_schedule: Optional[DataUpdateCommitInvoiceSchedule] = None - - name: Optional[str] = None - - netsuite_sales_order_id: Optional[str] = None - - priority: Optional[float] = None - """ - If multiple commits are applicable, the one with the lower priority will apply - first. - """ - - product_id: Optional[str] = None - - rate_type: Optional[Literal["COMMIT_RATE", "LIST_RATE"]] = None - """If set, the commit's rate type was updated to the specified value.""" - - rollover_fraction: Optional[float] = None - - specifiers: Optional[List[CommitSpecifierInput]] = None - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - Instead, to target usage by product or product tag, pass those values in the - body of `specifiers`. - """ - - -class DataUpdateCreditAccessScheduleAddScheduleItem(BaseModel): - amount: float - - ending_before: datetime - """RFC 3339 timestamp (exclusive)""" - - starting_at: datetime - """RFC 3339 timestamp (inclusive)""" - - -class DataUpdateCreditAccessScheduleRemoveScheduleItem(BaseModel): - id: str - - -class DataUpdateCreditAccessScheduleUpdateScheduleItem(BaseModel): - id: str - - amount: Optional[float] = None - - ending_before: Optional[datetime] = None - """RFC 3339 timestamp (exclusive)""" - - starting_at: Optional[datetime] = None - """RFC 3339 timestamp (inclusive)""" - - -class DataUpdateCreditAccessSchedule(BaseModel): - add_schedule_items: Optional[List[DataUpdateCreditAccessScheduleAddScheduleItem]] = None - - remove_schedule_items: Optional[List[DataUpdateCreditAccessScheduleRemoveScheduleItem]] = None - - update_schedule_items: Optional[List[DataUpdateCreditAccessScheduleUpdateScheduleItem]] = None - - -class DataUpdateCredit(BaseModel): - id: str - - access_schedule: Optional[DataUpdateCreditAccessSchedule] = None - - description: Optional[str] = None - - hierarchy_configuration: Optional[CommitHierarchyConfiguration] = None - """Optional configuration for credit hierarchy access control""" - - name: Optional[str] = None - - netsuite_sales_order_id: Optional[str] = None - - priority: Optional[float] = None - """ - If multiple credits are applicable, the one with the lower priority will apply - first. - """ - - rate_type: Optional[Literal["LIST_RATE", "COMMIT_RATE"]] = None - """If set, the credit's rate type was updated to the specified value.""" - - rollover_fraction: Optional[float] = None - - -class DataUpdateDiscountScheduleRecurringSchedule(BaseModel): - """Enter the unit price and quantity for the charge or instead only send the amount. - - If amount is sent, the unit price is assumed to be the amount and quantity is inferred to be 1. - """ - - amount_distribution: Literal["DIVIDED", "DIVIDED_ROUNDED", "EACH"] - - ending_before: datetime - """RFC 3339 timestamp (exclusive).""" - - frequency: Literal["MONTHLY", "QUARTERLY", "SEMI_ANNUAL", "ANNUAL", "WEEKLY"] - - starting_at: datetime - """RFC 3339 timestamp (inclusive).""" - - amount: Optional[float] = None - """Amount for the charge. - - Can be provided instead of unit_price and quantity. If amount is sent, the - unit_price is assumed to be the amount and quantity is inferred to be 1. - """ - - quantity: Optional[float] = None - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount and must be specified - with unit_price. If specified amount cannot be provided. - """ - - unit_price: Optional[float] = None - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified - with quantity. If specified amount cannot be provided. - """ - - -class DataUpdateDiscountScheduleScheduleItem(BaseModel): - timestamp: datetime - """timestamp of the scheduled event""" - - amount: Optional[float] = None - """Amount for the charge. - - Can be provided instead of unit_price and quantity. If amount is sent, the - unit_price is assumed to be the amount and quantity is inferred to be 1. - """ - - quantity: Optional[float] = None - """Quantity for the charge. - - Will be multiplied by unit_price to determine the amount and must be specified - with unit_price. If specified amount cannot be provided. - """ - - unit_price: Optional[float] = None - """Unit price for the charge. - - Will be multiplied by quantity to determine the amount and must be specified - with quantity. If specified amount cannot be provided. - """ - - -class DataUpdateDiscountSchedule(BaseModel): - """Must provide either schedule_items or recurring_schedule.""" - - credit_type_id: Optional[str] = None - """Defaults to USD (cents) if not passed.""" - - do_not_invoice: Optional[bool] = None - """This field is only applicable to commit invoice schedules. - - If true, this schedule will not generate an invoice. - """ - - recurring_schedule: Optional[DataUpdateDiscountScheduleRecurringSchedule] = None - """Enter the unit price and quantity for the charge or instead only send the - amount. - - If amount is sent, the unit price is assumed to be the amount and quantity is - inferred to be 1. - """ - - schedule_items: Optional[List[DataUpdateDiscountScheduleScheduleItem]] = None - """Either provide amount or provide both unit_price and quantity.""" - - -class DataUpdateDiscount(BaseModel): - id: str - - custom_fields: Optional[Dict[str, str]] = None - """Custom fields to be added eg. { "key1": "value1", "key2": "value2" }""" - - name: Optional[str] = None - - netsuite_sales_order_id: Optional[str] = None - - schedule: Optional[DataUpdateDiscountSchedule] = None - """Must provide either schedule_items or recurring_schedule.""" - - -class DataUpdatePrepaidBalanceThresholdConfigurationCommit(UpdateBaseThresholdCommit): - applicable_product_ids: Optional[List[str]] = None - """Which products the threshold commit applies to. - - If both applicable_product_ids and applicable_product_tags are not provided, the - commit applies to all products. - """ - - applicable_product_tags: Optional[List[str]] = None - """Which tags the threshold commit applies to. - - If both applicable_product_ids and applicable_product_tags are not provided, the - commit applies to all products. - """ - - specifiers: Optional[List[CommitSpecifierInput]] = None - """ - List of filters that determine what kind of customer usage draws down a commit - or credit. A customer's usage needs to meet the condition of at least one of the - specifiers to contribute to a commit's or credit's drawdown. This field cannot - be used together with `applicable_product_ids` or `applicable_product_tags`. - Instead, to target usage by product or product tag, pass those values in the - body of `specifiers`. - """ - - -class DataUpdatePrepaidBalanceThresholdConfiguration(BaseModel): - commit: Optional[DataUpdatePrepaidBalanceThresholdConfigurationCommit] = None - - custom_credit_type_id: Optional[str] = None - """ - If provided, the threshold, recharge-to amount, and the resulting threshold - commit amount will be in terms of this credit type instead of the fiat currency. - """ - - is_enabled: Optional[bool] = None - """ - When set to false, the contract will not be evaluated against the - threshold_amount. Toggling to true will result an immediate evaluation, - regardless of prior state. - """ - - payment_gate_config: Optional[PaymentGateConfigV2] = None - - recharge_to_amount: Optional[float] = None - """Specify the amount the balance should be recharged to.""" - - threshold_amount: Optional[float] = None - """Specify the threshold amount for the contract. - - Each time the contract's balance lowers to this amount, a threshold charge will - be initiated. - """ - - -class DataUpdateRecurringCommitAccessAmount(BaseModel): - quantity: Optional[float] = None - - unit_price: Optional[float] = None - - -class DataUpdateRecurringCommitInvoiceAmount(BaseModel): - quantity: Optional[float] = None - - unit_price: Optional[float] = None - - -class DataUpdateRecurringCommit(BaseModel): - id: str - - access_amount: Optional[DataUpdateRecurringCommitAccessAmount] = None - - ending_before: Optional[datetime] = None - - invoice_amount: Optional[DataUpdateRecurringCommitInvoiceAmount] = None - - rate_type: Optional[Literal["LIST_RATE", "COMMIT_RATE"]] = None - - -class DataUpdateRecurringCreditAccessAmount(BaseModel): - quantity: Optional[float] = None - - unit_price: Optional[float] = None - - -class DataUpdateRecurringCredit(BaseModel): - id: str - - access_amount: Optional[DataUpdateRecurringCreditAccessAmount] = None - - ending_before: Optional[datetime] = None - - rate_type: Optional[Literal["LIST_RATE", "COMMIT_RATE"]] = None - - -class DataUpdateRefundInvoice(BaseModel): - date: datetime - - invoice_id: str - - -class DataUpdateScheduledChargeInvoiceScheduleAddScheduleItem(BaseModel): - timestamp: datetime - - amount: Optional[float] = None - - quantity: Optional[float] = None - - unit_price: Optional[float] = None - - -class DataUpdateScheduledChargeInvoiceScheduleRemoveScheduleItem(BaseModel): - id: str - - -class DataUpdateScheduledChargeInvoiceScheduleUpdateScheduleItem(BaseModel): - id: str - - amount: Optional[float] = None - - quantity: Optional[float] = None - - timestamp: Optional[datetime] = None - - unit_price: Optional[float] = None - - -class DataUpdateScheduledChargeInvoiceSchedule(BaseModel): - add_schedule_items: Optional[List[DataUpdateScheduledChargeInvoiceScheduleAddScheduleItem]] = None - - remove_schedule_items: Optional[List[DataUpdateScheduledChargeInvoiceScheduleRemoveScheduleItem]] = None - - update_schedule_items: Optional[List[DataUpdateScheduledChargeInvoiceScheduleUpdateScheduleItem]] = None - - -class DataUpdateScheduledCharge(BaseModel): - id: str - - invoice_schedule: Optional[DataUpdateScheduledChargeInvoiceSchedule] = None - - name: Optional[str] = None - - netsuite_sales_order_id: Optional[str] = None - - -class DataUpdateSpendThresholdConfiguration(BaseModel): - commit: Optional[UpdateBaseThresholdCommit] = None - - is_enabled: Optional[bool] = None - """ - When set to false, the contract will not be evaluated against the - threshold_amount. Toggling to true will result an immediate evaluation, - regardless of prior state. - """ - - payment_gate_config: Optional[PaymentGateConfigV2] = None - - threshold_amount: Optional[float] = None - """Specify the threshold amount for the contract. - - Each time the contract's usage hits this amount, a threshold charge will be - initiated. - """ - - -class DataUpdateSubscriptionQuantityUpdate(BaseModel): - starting_at: datetime - - quantity: Optional[float] = None - - quantity_delta: Optional[float] = None - - -class DataUpdateSubscriptionSeatUpdatesAddSeatID(BaseModel): - seat_ids: List[str] - - starting_at: datetime - """Assigned seats will be added/removed starting at this date.""" - - -class DataUpdateSubscriptionSeatUpdatesAddUnassignedSeat(BaseModel): - quantity: float - """ - The number of unassigned seats on the subscription will increase/decrease by - this delta. Must be greater than 0. - """ - - starting_at: datetime - """Unassigned seats will be updated starting at this date.""" - - -class DataUpdateSubscriptionSeatUpdatesRemoveSeatID(BaseModel): - seat_ids: List[str] - - starting_at: datetime - """Assigned seats will be added/removed starting at this date.""" - - -class DataUpdateSubscriptionSeatUpdatesRemoveUnassignedSeat(BaseModel): - quantity: float - """ - The number of unassigned seats on the subscription will increase/decrease by - this delta. Must be greater than 0. - """ - - starting_at: datetime - """Unassigned seats will be updated starting at this date.""" - - -class DataUpdateSubscriptionSeatUpdates(BaseModel): - """Manage subscription seats for subscriptions in SEAT_BASED mode.""" - - add_seat_ids: Optional[List[DataUpdateSubscriptionSeatUpdatesAddSeatID]] = None - """Adds seat IDs to the subscription. - - If there are unassigned seats, the new seat IDs will fill these unassigned seats - and not increase the total subscription quantity. Otherwise, if there are more - new seat IDs than unassigned seats, the total subscription quantity will - increase. - """ - - add_unassigned_seats: Optional[List[DataUpdateSubscriptionSeatUpdatesAddUnassignedSeat]] = None - """Adds unassigned seats to the subscription. - - This will increase the total subscription quantity. - """ - - remove_seat_ids: Optional[List[DataUpdateSubscriptionSeatUpdatesRemoveSeatID]] = None - """Removes seat IDs from the subscription, if possible. - - If a seat ID is removed, the total subscription quantity will decrease. - Otherwise, if the seat ID is not found on the subscription, this is a no-op. - """ - - remove_unassigned_seats: Optional[List[DataUpdateSubscriptionSeatUpdatesRemoveUnassignedSeat]] = None - """Removes unassigned seats from the subscription. - - This will decrease the total subscription quantity if there are are unassigned - seats. - """ - - -class DataUpdateSubscription(BaseModel): - id: str - - ending_before: Optional[datetime] = None - - quantity_updates: Optional[List[DataUpdateSubscriptionQuantityUpdate]] = None - - seat_updates: Optional[DataUpdateSubscriptionSeatUpdates] = None - """Manage subscription seats for subscriptions in SEAT_BASED mode.""" - - -class Data(BaseModel): - id: str - - add_commits: Optional[List[DataAddCommit]] = None - - add_credits: Optional[List[DataAddCredit]] = None - - add_discounts: Optional[List[Discount]] = None - - add_overrides: Optional[List[DataAddOverride]] = None - - add_prepaid_balance_threshold_configuration: Optional[PrepaidBalanceThresholdConfigurationV2] = None - - add_pro_services: Optional[List[ProService]] = None - - add_recurring_commits: Optional[List[DataAddRecurringCommit]] = None - - add_recurring_credits: Optional[List[DataAddRecurringCredit]] = None - - add_reseller_royalties: Optional[List[DataAddResellerRoyalty]] = None - - add_scheduled_charges: Optional[List[DataAddScheduledCharge]] = None - - add_spend_threshold_configuration: Optional[SpendThresholdConfigurationV2] = None - - add_subscriptions: Optional[List[Subscription]] = None - """List of subscriptions on the contract.""" - - add_usage_filters: Optional[List[DataAddUsageFilter]] = None - - archive_commits: Optional[List[DataArchiveCommit]] = None - - archive_credits: Optional[List[DataArchiveCredit]] = None - - archive_scheduled_charges: Optional[List[DataArchiveScheduledCharge]] = None - - remove_overrides: Optional[List[DataRemoveOverride]] = None - - timestamp: Optional[datetime] = None - - uniqueness_key: Optional[str] = None - """Prevents the creation of duplicates. - - If a request to create a record is made with a previously used uniqueness key, a - new record will not be created and the request will fail with a 409 error. - """ - - update_commits: Optional[List[DataUpdateCommit]] = None - - update_contract_end_date: Optional[datetime] = None - - update_contract_name: Optional[str] = None - """Value to update the contract name to. - - If not provided, the contract name will remain unchanged. - """ - - update_credits: Optional[List[DataUpdateCredit]] = None - - update_discounts: Optional[List[DataUpdateDiscount]] = None - - update_prepaid_balance_threshold_configuration: Optional[DataUpdatePrepaidBalanceThresholdConfiguration] = None - - update_recurring_commits: Optional[List[DataUpdateRecurringCommit]] = None - - update_recurring_credits: Optional[List[DataUpdateRecurringCredit]] = None - - update_refund_invoices: Optional[List[DataUpdateRefundInvoice]] = None - - update_scheduled_charges: Optional[List[DataUpdateScheduledCharge]] = None - - update_spend_threshold_configuration: Optional[DataUpdateSpendThresholdConfiguration] = None - - update_subscriptions: Optional[List[DataUpdateSubscription]] = None - """Optional list of subscriptions to update.""" - - -class ContractGetEditHistoryResponse(BaseModel): - data: List[Data] diff --git a/src/metronome/types/v2/contract_list_params.py b/src/metronome/types/v2/contract_list_params.py deleted file mode 100644 index 884d14987..000000000 --- a/src/metronome/types/v2/contract_list_params.py +++ /dev/null @@ -1,44 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ..._utils import PropertyInfo - -__all__ = ["ContractListParams"] - - -class ContractListParams(TypedDict, total=False): - customer_id: Required[str] - - covering_date: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Optional RFC 3339 timestamp. - - Only include contracts active on the provided date. This cannot be provided if - starting_at filter is provided. - """ - - include_archived: bool - """Include archived contracts in the response.""" - - include_balance: bool - """Include the balance of credits and commits in the response. - - Setting this flag may cause the response to be slower. - """ - - include_ledgers: bool - """Include commit/credit ledgers in the response. - - Setting this flag may cause the response to be slower. - """ - - starting_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Optional RFC 3339 timestamp. - - Only include contracts that started on or after this date. This cannot be - provided if covering_date filter is provided. - """ diff --git a/src/metronome/types/v2/contract_list_response.py b/src/metronome/types/v2/contract_list_response.py deleted file mode 100644 index a869d665d..000000000 --- a/src/metronome/types/v2/contract_list_response.py +++ /dev/null @@ -1,12 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from typing import List - -from ..._models import BaseModel -from ..shared.contract_v2 import ContractV2 - -__all__ = ["ContractListResponse"] - - -class ContractListResponse(BaseModel): - data: List[ContractV2] diff --git a/src/metronome/types/v2/contract_retrieve_params.py b/src/metronome/types/v2/contract_retrieve_params.py deleted file mode 100644 index 99a1c0c9b..000000000 --- a/src/metronome/types/v2/contract_retrieve_params.py +++ /dev/null @@ -1,37 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from __future__ import annotations - -from typing import Union -from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict - -from ..._utils import PropertyInfo - -__all__ = ["ContractRetrieveParams"] - - -class ContractRetrieveParams(TypedDict, total=False): - contract_id: Required[str] - - customer_id: Required[str] - - as_of_date: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] - """Optional RFC 3339 timestamp. - - Return the contract as of this date. Cannot be used with include_ledgers - parameter. - """ - - include_balance: bool - """Include the balance of credits and commits in the response. - - Setting this flag may cause the query to be slower. - """ - - include_ledgers: bool - """Include commit/credit ledgers in the response. - - Setting this flag may cause the query to be slower. Cannot be used with - as_of_date parameter. - """ diff --git a/src/metronome/types/v2/contract_retrieve_response.py b/src/metronome/types/v2/contract_retrieve_response.py deleted file mode 100644 index 7e3027d93..000000000 --- a/src/metronome/types/v2/contract_retrieve_response.py +++ /dev/null @@ -1,10 +0,0 @@ -# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -from ..._models import BaseModel -from ..shared.contract_v2 import ContractV2 - -__all__ = ["ContractRetrieveResponse"] - - -class ContractRetrieveResponse(BaseModel): - data: ContractV2 From 1ce24a05ddf877450daa1e89ef8ade8f6502f999 Mon Sep 17 00:00:00 2001 From: mahamed eltorky <236695151+samarsamer251-glitch@users.noreply.github.com> Date: Fri, 27 Mar 2026 00:40:52 +0200 Subject: [PATCH 10/17] Delete .gitignore --- .gitignore | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 .gitignore diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 95ceb189a..000000000 --- a/.gitignore +++ /dev/null @@ -1,15 +0,0 @@ -.prism.log -_dev - -__pycache__ -.mypy_cache - -dist - -.venv -.idea - -.env -.envrc -codegen.log -Brewfile.lock.json From e41609163b6e7e5385fa372a7a9a14d8127ed8a8 Mon Sep 17 00:00:00 2001 From: mahamed eltorky <236695151+samarsamer251-glitch@users.noreply.github.com> Date: Fri, 27 Mar 2026 00:41:03 +0200 Subject: [PATCH 11/17] Delete examples directory --- examples/.keep | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 examples/.keep diff --git a/examples/.keep b/examples/.keep deleted file mode 100644 index d8c73e937..000000000 --- a/examples/.keep +++ /dev/null @@ -1,4 +0,0 @@ -File generated from our OpenAPI spec by Stainless. - -This directory can be used to store example files demonstrating usage of this SDK. -It is ignored by Stainless code generation and its content (other than this keep file) won't be touched. \ No newline at end of file From c9e1fe8e0d6bf6ce713903aa6db9ce3a96d1176e Mon Sep 17 00:00:00 2001 From: mahamed eltorky <236695151+samarsamer251-glitch@users.noreply.github.com> Date: Fri, 27 Mar 2026 00:41:15 +0200 Subject: [PATCH 12/17] Delete .stats.yml --- .stats.yml | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 .stats.yml diff --git a/.stats.yml b/.stats.yml deleted file mode 100644 index 7b87650c5..000000000 --- a/.stats.yml +++ /dev/null @@ -1,4 +0,0 @@ -configured_endpoints: 117 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/metronome%2Fmetronome-85366e631d706905d84194f96fdd274eb124a43f9a2f7a49a84eea5d2886b818.yml -openapi_spec_hash: 7831d9e41e792a2cdec665ababcb8540 -config_hash: 3a1a6a76abf38ea6f1b40af26f659cfa From 56b4f801bd3fee4d3346859ecc70be6cae03cdef Mon Sep 17 00:00:00 2001 From: mahamed eltorky <236695151+samarsamer251-glitch@users.noreply.github.com> Date: Fri, 27 Mar 2026 00:41:27 +0200 Subject: [PATCH 13/17] Delete Brewfile --- Brewfile | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 Brewfile diff --git a/Brewfile b/Brewfile deleted file mode 100644 index 492ca37bb..000000000 --- a/Brewfile +++ /dev/null @@ -1,2 +0,0 @@ -brew "rye" - From fc98dba688df6522968bc39283ec04e63f85d2d7 Mon Sep 17 00:00:00 2001 From: mahamed eltorky <236695151+samarsamer251-glitch@users.noreply.github.com> Date: Fri, 27 Mar 2026 00:41:39 +0200 Subject: [PATCH 14/17] Delete CONTRIBUTING.md --- CONTRIBUTING.md | 127 ------------------------------------------------ 1 file changed, 127 deletions(-) delete mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 1d1ede59f..000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,127 +0,0 @@ -## Setting up the environment - -### With Rye - -We use [Rye](https://rye.astral.sh/) to manage dependencies because it will automatically provision a Python environment with the expected Python version. To set it up, run: - -```sh -$ ./scripts/bootstrap -``` - -Or [install Rye manually](https://rye.astral.sh/guide/installation/) and run: - -```sh -$ rye sync --all-features -``` - -You can then run scripts using `rye run python script.py` or by activating the virtual environment: - -```sh -# Activate the virtual environment - https://docs.python.org/3/library/venv.html#how-venvs-work -$ source .venv/bin/activate - -# now you can omit the `rye run` prefix -$ python script.py -``` - -### Without Rye - -Alternatively if you don't want to install `Rye`, you can stick with the standard `pip` setup by ensuring you have the Python version specified in `.python-version`, create a virtual environment however you desire and then install dependencies using this command: - -```sh -$ pip install -r requirements-dev.lock -``` - -## Modifying/Adding code - -Most of the SDK is generated code. Modifications to code will be persisted between generations, but may -result in merge conflicts between manual patches and changes from the generator. The generator will never -modify the contents of the `src/metronome/lib/` and `examples/` directories. - -## Adding and running examples - -All files in the `examples/` directory are not modified by the generator and can be freely edited or added to. - -```py -# add an example to examples/.py - -#!/usr/bin/env -S rye run python -… -``` - -```sh -$ chmod +x examples/.py -# run the example against your api -$ ./examples/.py -``` - -## Using the repository from source - -If you’d like to use the repository from source, you can either install from git or link to a cloned repository: - -To install via git: - -```sh -$ pip install git+ssh://git@github.com/Metronome-Industries/metronome-python.git -``` - -Alternatively, you can build from source and install the wheel file: - -Building this package will create two files in the `dist/` directory, a `.tar.gz` containing the source files and a `.whl` that can be used to install the package efficiently. - -To create a distributable version of the library, all you have to do is run this command: - -```sh -$ rye build -# or -$ python -m build -``` - -Then to install: - -```sh -$ pip install ./path-to-wheel-file.whl -``` - -## Running tests - -Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests. - -```sh -$ ./scripts/mock -``` - -```sh -$ ./scripts/test -``` - -## Linting and formatting - -This repository uses [ruff](https://github.com/astral-sh/ruff) and -[black](https://github.com/psf/black) to format the code in the repository. - -To lint: - -```sh -$ ./scripts/lint -``` - -To format and fix all ruff issues automatically: - -```sh -$ ./scripts/format -``` - -## Publishing and releases - -Changes made to this repository via the automated release PR pipeline should publish to PyPI automatically. If -the changes aren't made through the automated pipeline, you may want to make releases manually. - -### Publish with a GitHub workflow - -You can release to package managers by using [the `Publish PyPI` GitHub action](https://www.github.com/Metronome-Industries/metronome-python/actions/workflows/publish-pypi.yml). This requires a setup organization or repository secret to be set up. - -### Publish manually - -If you need to manually release a package, you can run the `bin/publish-pypi` script with a `PYPI_TOKEN` set on -the environment. From 72473cf249be1d4e3a782bcfe91e0ffc80626797 Mon Sep 17 00:00:00 2001 From: mahamed eltorky <236695151+samarsamer251-glitch@users.noreply.github.com> Date: Fri, 27 Mar 2026 00:41:50 +0200 Subject: [PATCH 15/17] Delete LICENSE --- LICENSE | 201 -------------------------------------------------------- 1 file changed, 201 deletions(-) delete mode 100644 LICENSE diff --git a/LICENSE b/LICENSE deleted file mode 100644 index d61391a3d..000000000 --- a/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2026 Metronome - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. From 4733f1ba36459a147ce8e2b38665eb20bc2ed4e7 Mon Sep 17 00:00:00 2001 From: mahamed eltorky <236695151+samarsamer251-glitch@users.noreply.github.com> Date: Fri, 27 Mar 2026 00:42:01 +0200 Subject: [PATCH 16/17] Delete api.md --- api.md | 596 --------------------------------------------------------- 1 file changed, 596 deletions(-) delete mode 100644 api.md diff --git a/api.md b/api.md deleted file mode 100644 index bcc51e004..000000000 --- a/api.md +++ /dev/null @@ -1,596 +0,0 @@ -# Shared Types - -```python -from metronome.types import ( - BalanceFilter, - BaseThresholdCommit, - BaseUsageFilter, - Commit, - CommitHierarchyConfiguration, - CommitRate, - CommitSpecifier, - CommitSpecifierInput, - Contract, - ContractV2, - ContractWithoutAmendments, - Credit, - CreditTypeData, - Discount, - EventTypeFilter, - HierarchyConfiguration, - ID, - Override, - OverrideTier, - OverwriteRate, - PaymentGateConfig, - PaymentGateConfigV2, - PrepaidBalanceThresholdConfiguration, - PrepaidBalanceThresholdConfigurationV2, - PropertyFilter, - ProService, - Rate, - RecurringCommitSubscriptionConfig, - ScheduledCharge, - ScheduleDuration, - SchedulePointInTime, - SpendThresholdConfiguration, - SpendThresholdConfigurationV2, - Subscription, - Tier, - UpdateBaseThresholdCommit, -) -``` - -# V2 - -## Contracts - -Types: - -```python -from metronome.types.v2 import ( - ContractRetrieveResponse, - ContractListResponse, - ContractEditResponse, - ContractEditCommitResponse, - ContractEditCreditResponse, - ContractGetEditHistoryResponse, -) -``` - -Methods: - -- client.v2.contracts.retrieve(\*\*params) -> ContractRetrieveResponse -- client.v2.contracts.list(\*\*params) -> ContractListResponse -- client.v2.contracts.edit(\*\*params) -> ContractEditResponse -- client.v2.contracts.edit_commit(\*\*params) -> ContractEditCommitResponse -- client.v2.contracts.edit_credit(\*\*params) -> ContractEditCreditResponse -- client.v2.contracts.get_edit_history(\*\*params) -> ContractGetEditHistoryResponse - -# V1 - -## Alerts - -Types: - -```python -from metronome.types.v1 import AlertCreateResponse, AlertArchiveResponse -``` - -Methods: - -- client.v1.alerts.create(\*\*params) -> AlertCreateResponse -- client.v1.alerts.archive(\*\*params) -> AlertArchiveResponse - -## Plans - -Types: - -```python -from metronome.types.v1 import ( - PlanDetail, - PlanListResponse, - PlanGetDetailsResponse, - PlanListChargesResponse, - PlanListCustomersResponse, -) -``` - -Methods: - -- client.v1.plans.list(\*\*params) -> SyncCursorPage[PlanListResponse] -- client.v1.plans.get_details(\*, plan_id) -> PlanGetDetailsResponse -- client.v1.plans.list_charges(\*, plan_id, \*\*params) -> SyncCursorPage[PlanListChargesResponse] -- client.v1.plans.list_customers(\*, plan_id, \*\*params) -> SyncCursorPage[PlanListCustomersResponse] - -## CreditGrants - -Types: - -```python -from metronome.types.v1 import ( - CreditLedgerEntry, - RolloverAmountMaxAmount, - RolloverAmountMaxPercentage, - CreditGrantCreateResponse, - CreditGrantListResponse, - CreditGrantEditResponse, - CreditGrantListEntriesResponse, - CreditGrantVoidResponse, -) -``` - -Methods: - -- client.v1.credit_grants.create(\*\*params) -> CreditGrantCreateResponse -- client.v1.credit_grants.list(\*\*params) -> SyncCursorPage[CreditGrantListResponse] -- client.v1.credit_grants.edit(\*\*params) -> CreditGrantEditResponse -- client.v1.credit_grants.list_entries(\*\*params) -> SyncCursorPageWithoutLimit[CreditGrantListEntriesResponse] -- client.v1.credit_grants.void(\*\*params) -> CreditGrantVoidResponse - -## PricingUnits - -Types: - -```python -from metronome.types.v1 import PricingUnitListResponse -``` - -Methods: - -- client.v1.pricing_units.list(\*\*params) -> SyncCursorPage[PricingUnitListResponse] - -## Customers - -Types: - -```python -from metronome.types.v1 import ( - Customer, - CustomerDetail, - CustomerCreateResponse, - CustomerRetrieveResponse, - CustomerArchiveResponse, - CustomerArchiveBillingConfigurationsResponse, - CustomerListBillableMetricsResponse, - CustomerListCostsResponse, - CustomerPreviewEventsResponse, - CustomerRetrieveBillingConfigurationsResponse, - CustomerSetBillingConfigurationsResponse, - CustomerSetNameResponse, -) -``` - -Methods: - -- client.v1.customers.create(\*\*params) -> CustomerCreateResponse -- client.v1.customers.retrieve(\*, customer_id) -> CustomerRetrieveResponse -- client.v1.customers.list(\*\*params) -> SyncCursorPage[CustomerDetail] -- client.v1.customers.archive(\*\*params) -> CustomerArchiveResponse -- client.v1.customers.archive_billing_configurations(\*\*params) -> CustomerArchiveBillingConfigurationsResponse -- client.v1.customers.list_billable_metrics(\*, customer_id, \*\*params) -> SyncCursorPage[CustomerListBillableMetricsResponse] -- client.v1.customers.list_costs(\*, customer_id, \*\*params) -> SyncCursorPage[CustomerListCostsResponse] -- client.v1.customers.preview_events(\*, customer_id, \*\*params) -> CustomerPreviewEventsResponse -- client.v1.customers.retrieve_billing_configurations(\*\*params) -> CustomerRetrieveBillingConfigurationsResponse -- client.v1.customers.set_billing_configurations(\*\*params) -> CustomerSetBillingConfigurationsResponse -- client.v1.customers.set_ingest_aliases(\*, customer_id, \*\*params) -> None -- client.v1.customers.set_name(\*, customer_id, \*\*params) -> CustomerSetNameResponse -- client.v1.customers.update_config(\*, customer_id, \*\*params) -> None - -### Alerts - -Types: - -```python -from metronome.types.v1.customers import CustomerAlert, AlertRetrieveResponse -``` - -Methods: - -- client.v1.customers.alerts.retrieve(\*\*params) -> AlertRetrieveResponse -- client.v1.customers.alerts.list(\*\*params) -> SyncCursorPageWithoutLimit[CustomerAlert] -- client.v1.customers.alerts.reset(\*\*params) -> None - -### Plans - -Types: - -```python -from metronome.types.v1.customers import ( - PlanListResponse, - PlanAddResponse, - PlanEndResponse, - PlanListPriceAdjustmentsResponse, -) -``` - -Methods: - -- client.v1.customers.plans.list(\*, customer_id, \*\*params) -> SyncCursorPage[PlanListResponse] -- client.v1.customers.plans.add(\*, customer_id, \*\*params) -> PlanAddResponse -- client.v1.customers.plans.end(\*, customer_id, customer_plan_id, \*\*params) -> PlanEndResponse -- client.v1.customers.plans.list_price_adjustments(\*, customer_id, customer_plan_id, \*\*params) -> SyncCursorPage[PlanListPriceAdjustmentsResponse] - -### Invoices - -Types: - -```python -from metronome.types.v1.customers import ( - Invoice, - InvoiceRetrieveResponse, - InvoiceAddChargeResponse, - InvoiceListBreakdownsResponse, -) -``` - -Methods: - -- client.v1.customers.invoices.retrieve(\*, customer_id, invoice_id, \*\*params) -> InvoiceRetrieveResponse -- client.v1.customers.invoices.list(\*, customer_id, \*\*params) -> SyncCursorPage[Invoice] -- client.v1.customers.invoices.add_charge(\*, customer_id, \*\*params) -> InvoiceAddChargeResponse -- client.v1.customers.invoices.list_breakdowns(\*, customer_id, \*\*params) -> SyncCursorPage[InvoiceListBreakdownsResponse] -- client.v1.customers.invoices.retrieve_pdf(\*, customer_id, invoice_id) -> BinaryAPIResponse - -### BillingConfig - -Types: - -```python -from metronome.types.v1.customers import BillingConfigRetrieveResponse -``` - -Methods: - -- client.v1.customers.billing_config.create(\*, customer_id, billing_provider_type, \*\*params) -> None -- client.v1.customers.billing_config.retrieve(\*, customer_id, billing_provider_type) -> BillingConfigRetrieveResponse -- client.v1.customers.billing_config.delete(\*, customer_id, billing_provider_type) -> None - -### Commits - -Types: - -```python -from metronome.types.v1.customers import CommitCreateResponse, CommitUpdateEndDateResponse -``` - -Methods: - -- client.v1.customers.commits.create(\*\*params) -> CommitCreateResponse -- client.v1.customers.commits.list(\*\*params) -> SyncBodyCursorPage[Commit] -- client.v1.customers.commits.update_end_date(\*\*params) -> CommitUpdateEndDateResponse - -### Credits - -Types: - -```python -from metronome.types.v1.customers import CreditCreateResponse, CreditUpdateEndDateResponse -``` - -Methods: - -- client.v1.customers.credits.create(\*\*params) -> CreditCreateResponse -- client.v1.customers.credits.list(\*\*params) -> SyncBodyCursorPage[Credit] -- client.v1.customers.credits.update_end_date(\*\*params) -> CreditUpdateEndDateResponse - -### NamedSchedules - -Types: - -```python -from metronome.types.v1.customers import NamedScheduleRetrieveResponse -``` - -Methods: - -- client.v1.customers.named_schedules.retrieve(\*\*params) -> NamedScheduleRetrieveResponse -- client.v1.customers.named_schedules.update(\*\*params) -> None - -## Dashboards - -Types: - -```python -from metronome.types.v1 import DashboardGetEmbeddableURLResponse -``` - -Methods: - -- client.v1.dashboards.get_embeddable_url(\*\*params) -> DashboardGetEmbeddableURLResponse - -## Usage - -Types: - -```python -from metronome.types.v1 import UsageListResponse, UsageListWithGroupsResponse, UsageSearchResponse -``` - -Methods: - -- client.v1.usage.list(\*\*params) -> SyncCursorPageWithoutLimit[UsageListResponse] -- client.v1.usage.ingest(\*\*params) -> None -- client.v1.usage.list_with_groups(\*\*params) -> SyncCursorPage[UsageListWithGroupsResponse] -- client.v1.usage.search(\*\*params) -> UsageSearchResponse - -## AuditLogs - -Types: - -```python -from metronome.types.v1 import AuditLogListResponse -``` - -Methods: - -- client.v1.audit_logs.list(\*\*params) -> SyncCursorPage[AuditLogListResponse] - -## CustomFields - -Types: - -```python -from metronome.types.v1 import CustomFieldListKeysResponse -``` - -Methods: - -- client.v1.custom_fields.add_key(\*\*params) -> None -- client.v1.custom_fields.delete_values(\*\*params) -> None -- client.v1.custom_fields.list_keys(\*\*params) -> SyncCursorPageWithoutLimit[CustomFieldListKeysResponse] -- client.v1.custom_fields.remove_key(\*\*params) -> None -- client.v1.custom_fields.set_values(\*\*params) -> None - -## BillableMetrics - -Types: - -```python -from metronome.types.v1 import ( - BillableMetricCreateResponse, - BillableMetricRetrieveResponse, - BillableMetricListResponse, - BillableMetricArchiveResponse, -) -``` - -Methods: - -- client.v1.billable_metrics.create(\*\*params) -> BillableMetricCreateResponse -- client.v1.billable_metrics.retrieve(\*, billable_metric_id) -> BillableMetricRetrieveResponse -- client.v1.billable_metrics.list(\*\*params) -> SyncCursorPage[BillableMetricListResponse] -- client.v1.billable_metrics.archive(\*\*params) -> BillableMetricArchiveResponse - -## Services - -Types: - -```python -from metronome.types.v1 import ServiceListResponse -``` - -Methods: - -- client.v1.services.list() -> ServiceListResponse - -## Invoices - -Types: - -```python -from metronome.types.v1 import InvoiceRegenerateResponse, InvoiceVoidResponse -``` - -Methods: - -- client.v1.invoices.regenerate(\*\*params) -> InvoiceRegenerateResponse -- client.v1.invoices.void(\*\*params) -> InvoiceVoidResponse - -## Contracts - -Types: - -```python -from metronome.types.v1 import ( - ContractCreateResponse, - ContractRetrieveResponse, - ContractListResponse, - ContractAmendResponse, - ContractArchiveResponse, - ContractCreateHistoricalInvoicesResponse, - ContractGetNetBalanceResponse, - ContractListBalancesResponse, - ContractRetrieveRateScheduleResponse, - ContractRetrieveSubscriptionQuantityHistoryResponse, - ContractScheduleProServicesInvoiceResponse, - ContractUpdateEndDateResponse, -) -``` - -Methods: - -- client.v1.contracts.create(\*\*params) -> ContractCreateResponse -- client.v1.contracts.retrieve(\*\*params) -> ContractRetrieveResponse -- client.v1.contracts.list(\*\*params) -> ContractListResponse -- client.v1.contracts.add_manual_balance_entry(\*\*params) -> None -- client.v1.contracts.amend(\*\*params) -> ContractAmendResponse -- client.v1.contracts.archive(\*\*params) -> ContractArchiveResponse -- client.v1.contracts.create_historical_invoices(\*\*params) -> ContractCreateHistoricalInvoicesResponse -- client.v1.contracts.get_net_balance(\*\*params) -> ContractGetNetBalanceResponse -- client.v1.contracts.list_balances(\*\*params) -> SyncBodyCursorPage[ContractListBalancesResponse] -- client.v1.contracts.retrieve_rate_schedule(\*\*params) -> ContractRetrieveRateScheduleResponse -- client.v1.contracts.retrieve_subscription_quantity_history(\*\*params) -> ContractRetrieveSubscriptionQuantityHistoryResponse -- client.v1.contracts.schedule_pro_services_invoice(\*\*params) -> ContractScheduleProServicesInvoiceResponse -- client.v1.contracts.set_usage_filter(\*\*params) -> None -- client.v1.contracts.update_end_date(\*\*params) -> ContractUpdateEndDateResponse - -### Products - -Types: - -```python -from metronome.types.v1.contracts import ( - ProductListItemState, - QuantityConversion, - QuantityRounding, - ProductCreateResponse, - ProductRetrieveResponse, - ProductUpdateResponse, - ProductListResponse, - ProductArchiveResponse, -) -``` - -Methods: - -- client.v1.contracts.products.create(\*\*params) -> ProductCreateResponse -- client.v1.contracts.products.retrieve(\*\*params) -> ProductRetrieveResponse -- client.v1.contracts.products.update(\*\*params) -> ProductUpdateResponse -- client.v1.contracts.products.list(\*\*params) -> SyncCursorPage[ProductListResponse] -- client.v1.contracts.products.archive(\*\*params) -> ProductArchiveResponse - -### RateCards - -Types: - -```python -from metronome.types.v1.contracts import ( - RateCardCreateResponse, - RateCardRetrieveResponse, - RateCardUpdateResponse, - RateCardListResponse, - RateCardArchiveResponse, - RateCardRetrieveRateScheduleResponse, -) -``` - -Methods: - -- client.v1.contracts.rate_cards.create(\*\*params) -> RateCardCreateResponse -- client.v1.contracts.rate_cards.retrieve(\*\*params) -> RateCardRetrieveResponse -- client.v1.contracts.rate_cards.update(\*\*params) -> RateCardUpdateResponse -- client.v1.contracts.rate_cards.list(\*\*params) -> SyncCursorPage[RateCardListResponse] -- client.v1.contracts.rate_cards.archive(\*\*params) -> RateCardArchiveResponse -- client.v1.contracts.rate_cards.retrieve_rate_schedule(\*\*params) -> RateCardRetrieveRateScheduleResponse - -#### ProductOrders - -Types: - -```python -from metronome.types.v1.contracts.rate_cards import ( - ProductOrderUpdateResponse, - ProductOrderSetResponse, -) -``` - -Methods: - -- client.v1.contracts.rate_cards.product_orders.update(\*\*params) -> ProductOrderUpdateResponse -- client.v1.contracts.rate_cards.product_orders.set(\*\*params) -> ProductOrderSetResponse - -#### Rates - -Types: - -```python -from metronome.types.v1.contracts.rate_cards import ( - RateListResponse, - RateAddResponse, - RateAddManyResponse, -) -``` - -Methods: - -- client.v1.contracts.rate_cards.rates.list(\*\*params) -> SyncCursorPage[RateListResponse] -- client.v1.contracts.rate_cards.rates.add(\*\*params) -> RateAddResponse -- client.v1.contracts.rate_cards.rates.add_many(\*\*params) -> RateAddManyResponse - -#### NamedSchedules - -Types: - -```python -from metronome.types.v1.contracts.rate_cards import NamedScheduleRetrieveResponse -``` - -Methods: - -- client.v1.contracts.rate_cards.named_schedules.retrieve(\*\*params) -> NamedScheduleRetrieveResponse -- client.v1.contracts.rate_cards.named_schedules.update(\*\*params) -> None - -### NamedSchedules - -Types: - -```python -from metronome.types.v1.contracts import NamedScheduleRetrieveResponse -``` - -Methods: - -- client.v1.contracts.named_schedules.retrieve(\*\*params) -> NamedScheduleRetrieveResponse -- client.v1.contracts.named_schedules.update(\*\*params) -> None - -## Packages - -Types: - -```python -from metronome.types.v1 import ( - PackageCreateResponse, - PackageRetrieveResponse, - PackageListResponse, - PackageArchiveResponse, - PackageListContractsOnPackageResponse, -) -``` - -Methods: - -- client.v1.packages.create(\*\*params) -> PackageCreateResponse -- client.v1.packages.retrieve(\*\*params) -> PackageRetrieveResponse -- client.v1.packages.list(\*\*params) -> SyncCursorPage[PackageListResponse] -- client.v1.packages.archive(\*\*params) -> PackageArchiveResponse -- client.v1.packages.list_contracts_on_package(\*\*params) -> SyncCursorPage[PackageListContractsOnPackageResponse] - -## Payments - -Types: - -```python -from metronome.types.v1 import Payment, PaymentStatus, PaymentAttemptResponse, PaymentCancelResponse -``` - -Methods: - -- client.v1.payments.list(\*\*params) -> SyncBodyCursorPage[Payment] -- client.v1.payments.attempt(\*\*params) -> PaymentAttemptResponse -- client.v1.payments.cancel(\*\*params) -> PaymentCancelResponse - -## Settings - -Types: - -```python -from metronome.types.v1 import SettingUpsertAvalaraCredentialsResponse -``` - -Methods: - -- client.v1.settings.upsert_avalara_credentials(\*\*params) -> SettingUpsertAvalaraCredentialsResponse - -### BillingProviders - -Types: - -```python -from metronome.types.v1.settings import BillingProviderCreateResponse, BillingProviderListResponse -``` - -Methods: - -- client.v1.settings.billing_providers.create(\*\*params) -> BillingProviderCreateResponse -- client.v1.settings.billing_providers.list(\*\*params) -> BillingProviderListResponse From 2cea9582541f344ad6564cc86b7af23de914fac8 Mon Sep 17 00:00:00 2001 From: mahamed eltorky <236695151+samarsamer251-glitch@users.noreply.github.com> Date: Fri, 27 Mar 2026 00:42:11 +0200 Subject: [PATCH 17/17] Delete noxfile.py --- noxfile.py | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 noxfile.py diff --git a/noxfile.py b/noxfile.py deleted file mode 100644 index 53bca7ff2..000000000 --- a/noxfile.py +++ /dev/null @@ -1,9 +0,0 @@ -import nox - - -@nox.session(reuse_venv=True, name="test-pydantic-v1") -def test_pydantic_v1(session: nox.Session) -> None: - session.install("-r", "requirements-dev.lock") - session.install("pydantic<2") - - session.run("pytest", "--showlocals", "--ignore=tests/functional", *session.posargs)