diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 40293964..c8a8a4f7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,7 +12,6 @@ jobs: lint: name: lint runs-on: ubuntu-latest - steps: - uses: actions/checkout@v4 @@ -30,6 +29,7 @@ jobs: - name: Run lints run: ./scripts/lint + test: name: test runs-on: ubuntu-latest @@ -50,4 +50,3 @@ jobs: - name: Run tests run: ./scripts/test - diff --git a/.release-please-manifest.json b/.release-please-manifest.json index bf7fe4fa..ce692f94 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0-beta.3" + ".": "0.1.0-beta.4" } \ No newline at end of file diff --git a/.stats.yml b/.stats.yml index a0c4d47e..0744e0cd 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ configured_endpoints: 91 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/metronome%2Fmetronome-c4ec65355a30c07306ddff2c4a97411c2eb631a878583ce8bdd876a4fe2a5c96.yml +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/metronome%2Fmetronome-d45fa7bea4d4904432df31863500afbad8207834d9857d1d4b37549ed4621e10.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index f8234819..f2c3e461 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,99 @@ # Changelog +## 0.1.0-beta.4 (2025-01-23) + +Full Changelog: [v0.1.0-beta.3...v0.1.0-beta.4](https://github.com/Metronome-Industries/metronome-python/compare/v0.1.0-beta.3...v0.1.0-beta.4) + +### Features + +* **api:** api update ([#108](https://github.com/Metronome-Industries/metronome-python/issues/108)) ([a58c149](https://github.com/Metronome-Industries/metronome-python/commit/a58c14902c38e392eb61d690ab247edf42937f6e)) +* **api:** api update ([#109](https://github.com/Metronome-Industries/metronome-python/issues/109)) ([9e781b0](https://github.com/Metronome-Industries/metronome-python/commit/9e781b0f90d0466f3c8a9d782cbfee5e3362b3aa)) +* **api:** api update ([#111](https://github.com/Metronome-Industries/metronome-python/issues/111)) ([008bd54](https://github.com/Metronome-Industries/metronome-python/commit/008bd54b4708f25b2f8480bd7c2130cc51ee8668)) +* **api:** api update ([#113](https://github.com/Metronome-Industries/metronome-python/issues/113)) ([0973898](https://github.com/Metronome-Industries/metronome-python/commit/0973898da971367fca4be616e04aaff423ea7539)) +* **api:** api update ([#117](https://github.com/Metronome-Industries/metronome-python/issues/117)) ([28ed14a](https://github.com/Metronome-Industries/metronome-python/commit/28ed14ae3ab7d7454875a063af124631f7131119)) +* **api:** api update ([#118](https://github.com/Metronome-Industries/metronome-python/issues/118)) ([35b2858](https://github.com/Metronome-Industries/metronome-python/commit/35b2858964a4f700e20d0043925397f3757fa5a7)) +* **api:** api update ([#119](https://github.com/Metronome-Industries/metronome-python/issues/119)) ([2977ea1](https://github.com/Metronome-Industries/metronome-python/commit/2977ea1e20336adb46fa87601d7cd83d50ed43ff)) +* **api:** api update ([#120](https://github.com/Metronome-Industries/metronome-python/issues/120)) ([6d70b65](https://github.com/Metronome-Industries/metronome-python/commit/6d70b6560c1c2b2e31adf7687feaf9cab7083cbc)) +* **api:** api update ([#123](https://github.com/Metronome-Industries/metronome-python/issues/123)) ([6e879af](https://github.com/Metronome-Industries/metronome-python/commit/6e879af850dfbdc43fb59ff1d9aa3ff5fedaeee1)) +* **api:** api update ([#124](https://github.com/Metronome-Industries/metronome-python/issues/124)) ([6b92d9c](https://github.com/Metronome-Industries/metronome-python/commit/6b92d9c56d728320405d6eea3890f93f72448d3a)) +* **api:** api update ([#128](https://github.com/Metronome-Industries/metronome-python/issues/128)) ([c6a4123](https://github.com/Metronome-Industries/metronome-python/commit/c6a4123c5128c903849eeea47fe3719e9b42beda)) +* **api:** api update ([#131](https://github.com/Metronome-Industries/metronome-python/issues/131)) ([bf0c16e](https://github.com/Metronome-Industries/metronome-python/commit/bf0c16e40b390f6ec12df70cc67113096afd3111)) +* **api:** api update ([#136](https://github.com/Metronome-Industries/metronome-python/issues/136)) ([30f51ae](https://github.com/Metronome-Industries/metronome-python/commit/30f51ae371ea7d7c77cd2942683daa784f9e5ae5)) +* **api:** api update ([#139](https://github.com/Metronome-Industries/metronome-python/issues/139)) ([6fcda79](https://github.com/Metronome-Industries/metronome-python/commit/6fcda792f14ef951f36f2c7009bbcfc8d3857406)) +* **api:** api update ([#144](https://github.com/Metronome-Industries/metronome-python/issues/144)) ([63abf5d](https://github.com/Metronome-Industries/metronome-python/commit/63abf5d0af295024acbd0f31ac9fb1436927aefe)) +* **api:** api update ([#147](https://github.com/Metronome-Industries/metronome-python/issues/147)) ([3690360](https://github.com/Metronome-Industries/metronome-python/commit/3690360f8f0201ada6eb14f055803bc9062b14d4)) +* **api:** api update ([#148](https://github.com/Metronome-Industries/metronome-python/issues/148)) ([0e22565](https://github.com/Metronome-Industries/metronome-python/commit/0e22565a5ec0a1a08363806d88c684fe2ea50b64)) +* **api:** api update ([#150](https://github.com/Metronome-Industries/metronome-python/issues/150)) ([d027800](https://github.com/Metronome-Industries/metronome-python/commit/d027800ccad33753d1d3fd1656580b461374318e)) +* **api:** api update ([#156](https://github.com/Metronome-Industries/metronome-python/issues/156)) ([06e842b](https://github.com/Metronome-Industries/metronome-python/commit/06e842bd6424d166793697a18a0add5fbe4e7ee1)) +* **api:** api update ([#157](https://github.com/Metronome-Industries/metronome-python/issues/157)) ([c185997](https://github.com/Metronome-Industries/metronome-python/commit/c1859971c8caf7626b511568349b836b617ec669)) +* **api:** api update ([#158](https://github.com/Metronome-Industries/metronome-python/issues/158)) ([45e89f1](https://github.com/Metronome-Industries/metronome-python/commit/45e89f153886c808e7a39898eeb857e0f05bf287)) +* **api:** api update ([#160](https://github.com/Metronome-Industries/metronome-python/issues/160)) ([368fd85](https://github.com/Metronome-Industries/metronome-python/commit/368fd855524a98debfd5098c818b0cc942b02749)) +* **api:** api update ([#161](https://github.com/Metronome-Industries/metronome-python/issues/161)) ([109129d](https://github.com/Metronome-Industries/metronome-python/commit/109129d67fe3209dac24fcc4e8e15f17e6aca99e)) +* **api:** api update ([#163](https://github.com/Metronome-Industries/metronome-python/issues/163)) ([f8eb0ab](https://github.com/Metronome-Industries/metronome-python/commit/f8eb0ab0944e08dbed06f18b12dd7c0bbdbbe9cb)) +* **api:** api update ([#165](https://github.com/Metronome-Industries/metronome-python/issues/165)) ([3a868c4](https://github.com/Metronome-Industries/metronome-python/commit/3a868c4d502351e68a4da74286d8b3580a3ea86f)) +* **api:** api update ([#166](https://github.com/Metronome-Industries/metronome-python/issues/166)) ([e7ca427](https://github.com/Metronome-Industries/metronome-python/commit/e7ca427b85a09c4ed735464bdfd2ae5f486c96f0)) +* **api:** api update ([#171](https://github.com/Metronome-Industries/metronome-python/issues/171)) ([4389567](https://github.com/Metronome-Industries/metronome-python/commit/438956757ed829b38a44a6005b35772e0e695c42)) +* **api:** OpenAPI spec update via Stainless API ([#100](https://github.com/Metronome-Industries/metronome-python/issues/100)) ([23e4233](https://github.com/Metronome-Industries/metronome-python/commit/23e4233bc784c861d75d774b0ad9b9093f604d18)) +* **api:** OpenAPI spec update via Stainless API ([#105](https://github.com/Metronome-Industries/metronome-python/issues/105)) ([d53b0c0](https://github.com/Metronome-Industries/metronome-python/commit/d53b0c047bba46b022b98ab8617cb39d9aa8d4e5)) +* **api:** OpenAPI spec update via Stainless API ([#97](https://github.com/Metronome-Industries/metronome-python/issues/97)) ([1b9edd9](https://github.com/Metronome-Industries/metronome-python/commit/1b9edd91340ad039cc9e0d20b0912bd25594b0e2)) + + +### Bug Fixes + +* **client:** avoid OverflowError with very large retry counts ([#106](https://github.com/Metronome-Industries/metronome-python/issues/106)) ([465d868](https://github.com/Metronome-Industries/metronome-python/commit/465d86895931b326f9fec627df94e82b1b6800b4)) +* **client:** compat with new httpx 0.28.0 release ([#133](https://github.com/Metronome-Industries/metronome-python/issues/133)) ([5d8b9cc](https://github.com/Metronome-Industries/metronome-python/commit/5d8b9cc2cb99a4c3245203183cbe486cd4ed447c)) +* **client:** only call .close() when needed ([#153](https://github.com/Metronome-Industries/metronome-python/issues/153)) ([f8f67e6](https://github.com/Metronome-Industries/metronome-python/commit/f8f67e63c45836086260ff14d78e5547ce999f78)) +* correctly handle deserialising `cls` fields ([#159](https://github.com/Metronome-Industries/metronome-python/issues/159)) ([b26b63b](https://github.com/Metronome-Industries/metronome-python/commit/b26b63bb4b49ea7da790bd8da800ca1be0c8cbf6)) +* **tests:** make test_get_platform less flaky ([#168](https://github.com/Metronome-Industries/metronome-python/issues/168)) ([db126f2](https://github.com/Metronome-Industries/metronome-python/commit/db126f21197ee1e42462b86aa0a3a19f274b2564)) + + +### Chores + +* add missing isclass check ([#151](https://github.com/Metronome-Industries/metronome-python/issues/151)) ([e5fde7c](https://github.com/Metronome-Industries/metronome-python/commit/e5fde7c49a6da112c6a1b43b381bdbdf8b1b688c)) +* add repr to PageInfo class ([#107](https://github.com/Metronome-Industries/metronome-python/issues/107)) ([8306ee7](https://github.com/Metronome-Industries/metronome-python/commit/8306ee749c394960eb57be7c6f41bf808f1612f7)) +* **internal:** add support for parsing bool response content ([#104](https://github.com/Metronome-Industries/metronome-python/issues/104)) ([2253e61](https://github.com/Metronome-Industries/metronome-python/commit/2253e6118160b5a96f6fecb01afef46167524a07)) +* **internal:** add support for TypeAliasType ([#141](https://github.com/Metronome-Industries/metronome-python/issues/141)) ([17c7ae6](https://github.com/Metronome-Industries/metronome-python/commit/17c7ae6e8af47a6e716e50f5c94b24ab4a890a7b)) +* **internal:** avoid pytest-asyncio deprecation warning ([#169](https://github.com/Metronome-Industries/metronome-python/issues/169)) ([3136426](https://github.com/Metronome-Industries/metronome-python/commit/31364265a98eaa8eff463b6b533db3e2f57a13c5)) +* **internal:** bump httpx dependency ([#152](https://github.com/Metronome-Industries/metronome-python/issues/152)) ([337146f](https://github.com/Metronome-Industries/metronome-python/commit/337146f18a3fb67099a876e39fc22704bd923665)) +* **internal:** bump pydantic dependency ([#137](https://github.com/Metronome-Industries/metronome-python/issues/137)) ([a3d6204](https://github.com/Metronome-Industries/metronome-python/commit/a3d62042555f62a2fcdaca8bd9ab099649f24949)) +* **internal:** bump pyright ([#134](https://github.com/Metronome-Industries/metronome-python/issues/134)) ([e313f0a](https://github.com/Metronome-Industries/metronome-python/commit/e313f0a5e6619457c0111c07a08fd57179ce0854)) +* **internal:** bump pyright ([#140](https://github.com/Metronome-Industries/metronome-python/issues/140)) ([24f5bf0](https://github.com/Metronome-Industries/metronome-python/commit/24f5bf0075265818594feb0aa4f19f035e412e99)) +* **internal:** bump pyright dependency ([#164](https://github.com/Metronome-Industries/metronome-python/issues/164)) ([6a2460f](https://github.com/Metronome-Industries/metronome-python/commit/6a2460f8097738059c33fde596d879566298e163)) +* **internal:** codegen related update ([#101](https://github.com/Metronome-Industries/metronome-python/issues/101)) ([b946911](https://github.com/Metronome-Industries/metronome-python/commit/b946911194053715b04abf7e7b430c95e46a460c)) +* **internal:** codegen related update ([#102](https://github.com/Metronome-Industries/metronome-python/issues/102)) ([9cbc145](https://github.com/Metronome-Industries/metronome-python/commit/9cbc145ec42ebefdfbca884ee98494ea70b8265b)) +* **internal:** codegen related update ([#103](https://github.com/Metronome-Industries/metronome-python/issues/103)) ([2ed9f53](https://github.com/Metronome-Industries/metronome-python/commit/2ed9f539743b94821193900687ac15d85d9c5346)) +* **internal:** codegen related update ([#149](https://github.com/Metronome-Industries/metronome-python/issues/149)) ([c30e9bf](https://github.com/Metronome-Industries/metronome-python/commit/c30e9bfb788a839943d3bc55dba69b139734bc98)) +* **internal:** codegen related update ([#155](https://github.com/Metronome-Industries/metronome-python/issues/155)) ([bdfb2d0](https://github.com/Metronome-Industries/metronome-python/commit/bdfb2d005968b4890e1b31dd8e7666b95f907eee)) +* **internal:** codegen related update ([#98](https://github.com/Metronome-Industries/metronome-python/issues/98)) ([b4b48c0](https://github.com/Metronome-Industries/metronome-python/commit/b4b48c0421234322967999892118c145c31900df)) +* **internal:** exclude mypy from running on tests ([#132](https://github.com/Metronome-Industries/metronome-python/issues/132)) ([2917f6e](https://github.com/Metronome-Industries/metronome-python/commit/2917f6ee6b61ec96afc5942cc15f5b02b61d3ad6)) +* **internal:** fix compat model_dump method when warnings are passed ([#127](https://github.com/Metronome-Industries/metronome-python/issues/127)) ([288a77f](https://github.com/Metronome-Industries/metronome-python/commit/288a77fb418850fd1564c1ca18bcc49a6e0751c8)) +* **internal:** fix some typos ([#146](https://github.com/Metronome-Industries/metronome-python/issues/146)) ([7a35c26](https://github.com/Metronome-Industries/metronome-python/commit/7a35c2649bb9871c6bc2db71eb1dd8635490b075)) +* **internal:** minor formatting changes ([#172](https://github.com/Metronome-Industries/metronome-python/issues/172)) ([986fa49](https://github.com/Metronome-Industries/metronome-python/commit/986fa496184c7f4b480ac5833e358e57f60a6f4c)) +* **internal:** minor style changes ([#170](https://github.com/Metronome-Industries/metronome-python/issues/170)) ([20e89dc](https://github.com/Metronome-Industries/metronome-python/commit/20e89dcb8393c4b4e55fc61bed1bfe88beb9314d)) +* **internal:** remove some duplicated imports ([#142](https://github.com/Metronome-Industries/metronome-python/issues/142)) ([3cf4086](https://github.com/Metronome-Industries/metronome-python/commit/3cf4086d362bab08fe31783a037dcf8f8d6a2608)) +* **internal:** update deps ([#162](https://github.com/Metronome-Industries/metronome-python/issues/162)) ([db5dc45](https://github.com/Metronome-Industries/metronome-python/commit/db5dc45b2f2f9e4b71e00de08997fe6e09eda9e1)) +* **internal:** updated imports ([#143](https://github.com/Metronome-Industries/metronome-python/issues/143)) ([29abf00](https://github.com/Metronome-Industries/metronome-python/commit/29abf005793a3702d235ec0aeeaeaf59dc1f7033)) +* make the `Omit` type public ([#135](https://github.com/Metronome-Industries/metronome-python/issues/135)) ([85f1025](https://github.com/Metronome-Industries/metronome-python/commit/85f1025c763cb62930e618379f9b24e798200a7b)) +* rebuild project due to codegen change ([#110](https://github.com/Metronome-Industries/metronome-python/issues/110)) ([5cb0771](https://github.com/Metronome-Industries/metronome-python/commit/5cb0771a536431651843c40e88b069e87b6408b2)) +* rebuild project due to codegen change ([#112](https://github.com/Metronome-Industries/metronome-python/issues/112)) ([086bed0](https://github.com/Metronome-Industries/metronome-python/commit/086bed0b5ddc8e23b614be02abe0f9d73babbfda)) +* rebuild project due to codegen change ([#114](https://github.com/Metronome-Industries/metronome-python/issues/114)) ([d142e14](https://github.com/Metronome-Industries/metronome-python/commit/d142e14313cefcd6e12a6a382e690eda42973629)) +* rebuild project due to codegen change ([#115](https://github.com/Metronome-Industries/metronome-python/issues/115)) ([7b5ba26](https://github.com/Metronome-Industries/metronome-python/commit/7b5ba2664bab16fcd6ba7b82f67083d7bb8f7cd0)) +* rebuild project due to codegen change ([#116](https://github.com/Metronome-Industries/metronome-python/issues/116)) ([c01f739](https://github.com/Metronome-Industries/metronome-python/commit/c01f739eb6730598b6386d424de1cdfb03f0d188)) +* rebuild project due to codegen change ([#121](https://github.com/Metronome-Industries/metronome-python/issues/121)) ([f5da454](https://github.com/Metronome-Industries/metronome-python/commit/f5da4547cf574b22dfbfcf53edcde80a65c09e10)) +* rebuild project due to codegen change ([#122](https://github.com/Metronome-Industries/metronome-python/issues/122)) ([1e76c7d](https://github.com/Metronome-Industries/metronome-python/commit/1e76c7db771e85d6b752f6b39de6e548c93fbf2b)) +* rebuild project due to codegen change ([#125](https://github.com/Metronome-Industries/metronome-python/issues/125)) ([8ad959f](https://github.com/Metronome-Industries/metronome-python/commit/8ad959f010f90a4fc862fd1d8d4bc0d2e76454ae)) +* rebuild project due to codegen change ([#126](https://github.com/Metronome-Industries/metronome-python/issues/126)) ([a864791](https://github.com/Metronome-Industries/metronome-python/commit/a8647918c7477a85016ae666e54c9790d3d99bbd)) +* remove now unused `cached-property` dep ([#130](https://github.com/Metronome-Industries/metronome-python/issues/130)) ([9a3f84b](https://github.com/Metronome-Industries/metronome-python/commit/9a3f84bb7b53cc2e3c93787d49742d78ec5b3922)) + + +### Documentation + +* add info log level to readme ([#129](https://github.com/Metronome-Industries/metronome-python/issues/129)) ([670d5ab](https://github.com/Metronome-Industries/metronome-python/commit/670d5ab4aa1d5f77e085c7670acbeeac35a62a79)) +* fix typos ([#154](https://github.com/Metronome-Industries/metronome-python/issues/154)) ([2fd0635](https://github.com/Metronome-Industries/metronome-python/commit/2fd06359cefeab3cf17dee380bdf06d6525fed12)) +* **raw responses:** fix duplicate `the` ([#167](https://github.com/Metronome-Industries/metronome-python/issues/167)) ([5afb7a8](https://github.com/Metronome-Industries/metronome-python/commit/5afb7a86af029e074032962e57e187856c0f43b5)) +* **readme:** example snippet for client context manager ([#145](https://github.com/Metronome-Industries/metronome-python/issues/145)) ([373b0bc](https://github.com/Metronome-Industries/metronome-python/commit/373b0bc94476027eca1c608ba655bd9728657556)) +* **readme:** fix http client proxies example ([#138](https://github.com/Metronome-Industries/metronome-python/issues/138)) ([f9c9290](https://github.com/Metronome-Industries/metronome-python/commit/f9c9290fcfd0abfac1b5203cee6f7635ae184f6f)) + ## 0.1.0-beta.3 (2024-09-20) Full Changelog: [v0.1.0-beta.2...v0.1.0-beta.3](https://github.com/Metronome-Industries/metronome-python/compare/v0.1.0-beta.2...v0.1.0-beta.3) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 52b9acc2..0fec5615 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,9 +2,13 @@ ### With Rye -We use [Rye](https://rye.astral.sh/) to manage dependencies so we highly recommend [installing it](https://rye.astral.sh/guide/installation/) as it will automatically provision a Python environment with the expected Python version. +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: -After installing Rye, you'll just have to run this command: +```sh +$ ./scripts/bootstrap +``` + +Or [install Rye manually](https://rye.astral.sh/guide/installation/) and run: ```sh $ rye sync --all-features @@ -39,17 +43,17 @@ modify the contents of the `src/metronome/lib/` and `examples/` directories. All files in the `examples/` directory are not modified by the generator and can be freely edited or added to. -```bash +```py # add an example to examples/.py #!/usr/bin/env -S rye run python … ``` -``` -chmod +x examples/.py +```sh +$ chmod +x examples/.py # run the example against your api -./examples/.py +$ ./examples/.py ``` ## Using the repository from source @@ -58,8 +62,8 @@ If you’d like to use the repository from source, you can either install from g To install via git: -```bash -pip install git+ssh://git@github.com/Metronome-Industries/metronome-python.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: @@ -68,29 +72,29 @@ Building this package will create two files in the `dist/` directory, a `.tar.gz To create a distributable version of the library, all you have to do is run this command: -```bash -rye build +```sh +$ rye build # or -python -m build +$ python -m build ``` Then to install: ```sh -pip install ./path-to-wheel-file.whl +$ 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. -```bash +```sh # you will need npm installed -npx prism mock path/to/your/openapi.yml +$ npx prism mock path/to/your/openapi.yml ``` -```bash -rye run pytest +```sh +$ ./scripts/test ``` ## Linting and formatting @@ -100,14 +104,14 @@ This repository uses [ruff](https://github.com/astral-sh/ruff) and To lint: -```bash -rye run lint +```sh +$ ./scripts/lint ``` To format and fix all ruff issues automatically: -```bash -rye run format +```sh +$ ./scripts/format ``` ## Publishing and releases diff --git a/LICENSE b/LICENSE index c93770a4..5ab3320c 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2024 Metronome + Copyright 2025 Metronome Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 47e1797c..3b3216be 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [![PyPI version](https://img.shields.io/pypi/v/metronome-sdk.svg)](https://pypi.org/project/metronome-sdk/) -The Metronome Python library provides convenient access to the Metronome REST API from any Python 3.7+ +The Metronome Python library provides convenient access to the Metronome REST API from any Python 3.8+ 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). @@ -30,8 +30,7 @@ import os from metronome import Metronome client = Metronome( - # This is the default and can be omitted - bearer_token=os.environ.get("METRONOME_BEARER_TOKEN"), + bearer_token=os.environ.get("METRONOME_BEARER_TOKEN"), # This is the default and can be omitted ) client.usage.ingest( @@ -61,8 +60,7 @@ import asyncio from metronome import AsyncMetronome client = AsyncMetronome( - # This is the default and can be omitted - bearer_token=os.environ.get("METRONOME_BEARER_TOKEN"), + bearer_token=os.environ.get("METRONOME_BEARER_TOKEN"), # This is the default and can be omitted ) @@ -189,7 +187,7 @@ except metronome.APIStatusError as e: print(e.response) ``` -Error codes are as followed: +Error codes are as follows: | Status Code | Error Type | | ----------- | -------------------------- | @@ -266,12 +264,14 @@ Note that requests that time out are [retried twice by default](#retries). 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 `debug`. +You can enable logging by setting the environment variable `METRONOME_LOG` to `info`. ```shell -$ export METRONOME_LOG=debug +$ 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`: @@ -334,8 +334,7 @@ If you need to access undocumented endpoints, params, or response properties, th #### 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) will be respected when making this -request. +http verbs. Options on the client will be respected (such as retries) when making this request. ```py import httpx @@ -364,18 +363,19 @@ can also get all the extra fields on the Pydantic model as a dict with 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 -- Custom transports +- 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( - proxies="http://my.test.proxy.example.com", + proxy="http://my.test.proxy.example.com", transport=httpx.HTTPTransport(local_address="0.0.0.0"), ), ) @@ -391,12 +391,22 @@ client.with_options(http_client=DefaultHttpxClient(...)) 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)_. +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. @@ -416,4 +426,8 @@ print(metronome.__version__) ## Requirements -Python 3.7 or higher. +Python 3.8 or higher. + +## Contributing + +See [the contributing documentation](./CONTRIBUTING.md). diff --git a/api.md b/api.md index 1d9f4d48..f0fda583 100644 --- a/api.md +++ b/api.md @@ -6,7 +6,7 @@ from metronome.types import ( Commit, ContractWithoutAmendments, Credit, - CreditType, + CreditTypeData, Discount, EventTypeFilter, ID, @@ -51,9 +51,9 @@ from metronome.types import ( Methods: - client.plans.list(\*\*params) -> SyncCursorPage[PlanListResponse] -- client.plans.get_details(plan_id) -> PlanGetDetailsResponse -- client.plans.list_charges(plan_id, \*\*params) -> SyncCursorPage[PlanListChargesResponse] -- client.plans.list_customers(plan_id, \*\*params) -> SyncCursorPage[PlanListCustomersResponse] +- client.plans.get_details(\*, plan_id) -> PlanGetDetailsResponse +- client.plans.list_charges(\*, plan_id, \*\*params) -> SyncCursorPage[PlanListChargesResponse] +- client.plans.list_customers(\*, plan_id, \*\*params) -> SyncCursorPage[PlanListCustomersResponse] # CreditGrants @@ -102,14 +102,14 @@ from metronome.types import ( Methods: - client.customers.create(\*\*params) -> CustomerCreateResponse -- client.customers.retrieve(customer_id) -> CustomerRetrieveResponse +- client.customers.retrieve(\*, customer_id) -> CustomerRetrieveResponse - client.customers.list(\*\*params) -> SyncCursorPage[CustomerDetail] - client.customers.archive(\*\*params) -> CustomerArchiveResponse -- client.customers.list_billable_metrics(customer_id, \*\*params) -> SyncCursorPage[CustomerListBillableMetricsResponse] -- client.customers.list_costs(customer_id, \*\*params) -> SyncCursorPage[CustomerListCostsResponse] -- client.customers.set_ingest_aliases(customer_id, \*\*params) -> None -- client.customers.set_name(customer_id, \*\*params) -> CustomerSetNameResponse -- client.customers.update_config(customer_id, \*\*params) -> None +- client.customers.list_billable_metrics(\*, customer_id, \*\*params) -> SyncCursorPage[CustomerListBillableMetricsResponse] +- client.customers.list_costs(\*, customer_id, \*\*params) -> SyncCursorPage[CustomerListCostsResponse] +- client.customers.set_ingest_aliases(\*, customer_id, \*\*params) -> None +- client.customers.set_name(\*, customer_id, \*\*params) -> CustomerSetNameResponse +- client.customers.update_config(\*, customer_id, \*\*params) -> None ## Alerts @@ -140,10 +140,10 @@ from metronome.types.customers import ( Methods: -- client.customers.plans.list(customer_id, \*\*params) -> SyncCursorPage[PlanListResponse] -- client.customers.plans.add(customer_id, \*\*params) -> PlanAddResponse -- client.customers.plans.end(customer_plan_id, \*, customer_id, \*\*params) -> PlanEndResponse -- client.customers.plans.list_price_adjustments(customer_plan_id, \*, customer_id, \*\*params) -> SyncCursorPage[PlanListPriceAdjustmentsResponse] +- client.customers.plans.list(\*, customer_id, \*\*params) -> SyncCursorPage[PlanListResponse] +- client.customers.plans.add(\*, customer_id, \*\*params) -> PlanAddResponse +- client.customers.plans.end(\*, customer_id, customer_plan_id, \*\*params) -> PlanEndResponse +- client.customers.plans.list_price_adjustments(\*, customer_id, customer_plan_id, \*\*params) -> SyncCursorPage[PlanListPriceAdjustmentsResponse] ## Invoices @@ -160,10 +160,10 @@ from metronome.types.customers import ( Methods: -- client.customers.invoices.retrieve(invoice_id, \*, customer_id, \*\*params) -> InvoiceRetrieveResponse -- client.customers.invoices.list(customer_id, \*\*params) -> SyncCursorPage[Invoice] -- client.customers.invoices.add_charge(customer_id, \*\*params) -> InvoiceAddChargeResponse -- client.customers.invoices.list_breakdowns(customer_id, \*\*params) -> SyncCursorPage[InvoiceListBreakdownsResponse] +- client.customers.invoices.retrieve(\*, customer_id, invoice_id, \*\*params) -> InvoiceRetrieveResponse +- client.customers.invoices.list(\*, customer_id, \*\*params) -> SyncCursorPage[Invoice] +- client.customers.invoices.add_charge(\*, customer_id, \*\*params) -> InvoiceAddChargeResponse +- client.customers.invoices.list_breakdowns(\*, customer_id, \*\*params) -> SyncCursorPage[InvoiceListBreakdownsResponse] ## BillingConfig @@ -175,9 +175,9 @@ from metronome.types.customers import BillingConfigRetrieveResponse Methods: -- client.customers.billing_config.create(billing_provider_type, \*, customer_id, \*\*params) -> None -- client.customers.billing_config.retrieve(billing_provider_type, \*, customer_id) -> BillingConfigRetrieveResponse -- client.customers.billing_config.delete(billing_provider_type, \*, customer_id) -> None +- client.customers.billing_config.create(\*, customer_id, billing_provider_type, \*\*params) -> None +- client.customers.billing_config.retrieve(\*, customer_id, billing_provider_type) -> BillingConfigRetrieveResponse +- client.customers.billing_config.delete(\*, customer_id, billing_provider_type) -> None ## Commits @@ -298,7 +298,7 @@ from metronome.types import ( Methods: - client.billable_metrics.create(\*\*params) -> BillableMetricCreateResponse -- client.billable_metrics.retrieve(billable_metric_id) -> BillableMetricRetrieveResponse +- client.billable_metrics.retrieve(\*, billable_metric_id) -> BillableMetricRetrieveResponse - client.billable_metrics.list(\*\*params) -> SyncCursorPage[BillableMetricListResponse] - client.billable_metrics.archive(\*\*params) -> BillableMetricArchiveResponse diff --git a/mypy.ini b/mypy.ini index 7ce5547b..4e7b1761 100644 --- a/mypy.ini +++ b/mypy.ini @@ -5,7 +5,10 @@ show_error_codes = True # Exclude _files.py because mypy isn't smart enough to apply # the correct type narrowing and as this is an internal module # it's fine to just use Pyright. -exclude = ^(src/metronome/_files\.py|_dev/.*\.py)$ +# +# We also exclude our `tests` as mypy doesn't always infer +# types correctly and Pyright will still catch any type errors. +exclude = ^(src/metronome/_files\.py|_dev/.*\.py|tests/.*)$ strict_equality = True implicit_reexport = True @@ -38,7 +41,7 @@ cache_fine_grained = True # ``` # Changing this codegen to make mypy happy would increase complexity # and would not be worth it. -disable_error_code = func-returns-value +disable_error_code = func-returns-value,overload-cannot-match # https://github.com/python/mypy/issues/12162 [mypy.overrides] diff --git a/pyproject.toml b/pyproject.toml index d20c4a40..8627ea81 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "metronome-sdk" -version = "0.1.0-beta.3" +version = "0.1.0-beta.4" description = "The official Python library for the metronome API" dynamic = ["readme"] license = "Apache-2.0" @@ -10,17 +10,15 @@ authors = [ dependencies = [ "httpx>=0.23.0, <1", "pydantic>=1.9.0, <3", - "typing-extensions>=4.7, <5", + "typing-extensions>=4.10, <5", "anyio>=3.5.0, <5", "distro>=1.7.0, <2", "sniffio", - "cached-property; python_version < '3.8'", ] -requires-python = ">= 3.7" +requires-python = ">= 3.8" classifiers = [ "Typing :: Typed", "Intended Audience :: Developers", - "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", @@ -56,6 +54,7 @@ dev-dependencies = [ "dirty-equals>=0.6.0", "importlib-metadata>=6.7.0", "rich>=13.7.1", + "nest_asyncio==1.6.0", ] [tool.rye.scripts] @@ -63,11 +62,11 @@ format = { chain = [ "format:ruff", "format:docs", "fix:ruff", + # run formatting again to fix any inconsistencies when imports are stripped + "format:ruff", ]} -"format:black" = "black ." "format:docs" = "python scripts/utils/ruffen-docs.py README.md api.md" "format:ruff" = "ruff format" -"format:isort" = "isort ." "lint" = { chain = [ "check:ruff", @@ -125,15 +124,12 @@ path = "README.md" pattern = '\[(.+?)\]\(((?!https?://)\S+?)\)' replacement = '[\1](https://github.com/Metronome-Industries/metronome-python/tree/main/\g<2>)' -[tool.black] -line-length = 120 -target-version = ["py37"] - [tool.pytest.ini_options] testpaths = ["tests"] addopts = "--tb=short" xfail_strict = true asyncio_mode = "auto" +asyncio_default_fixture_loop_scope = "session" filterwarnings = [ "error" ] @@ -143,7 +139,7 @@ filterwarnings = [ # there are a couple of flags that are still disabled by # default in strict mode as they are experimental and niche. typeCheckingMode = "strict" -pythonVersion = "3.7" +pythonVersion = "3.8" exclude = [ "_dev", diff --git a/requirements-dev.lock b/requirements-dev.lock index 47f367aa..b641f814 100644 --- a/requirements-dev.lock +++ b/requirements-dev.lock @@ -16,8 +16,6 @@ anyio==4.4.0 # via metronome-sdk argcomplete==3.1.2 # via nox -attrs==23.1.0 - # via pytest certifi==2023.7.22 # via httpcore # via httpx @@ -28,15 +26,16 @@ distlib==0.3.7 # via virtualenv distro==1.8.0 # via metronome-sdk -exceptiongroup==1.1.3 +exceptiongroup==1.2.2 # via anyio + # via pytest filelock==3.12.4 # via virtualenv h11==0.14.0 # via httpcore httpcore==1.0.2 # via httpx -httpx==0.25.2 +httpx==0.28.1 # via metronome-sdk # via respx idna==3.4 @@ -49,9 +48,10 @@ markdown-it-py==3.0.0 # via rich mdurl==0.1.2 # via markdown-it-py -mypy==1.11.2 +mypy==1.14.1 mypy-extensions==1.0.0 # via mypy +nest-asyncio==1.6.0 nodeenv==1.8.0 # via pyright nox==2023.4.22 @@ -60,45 +60,43 @@ packaging==23.2 # via pytest platformdirs==3.11.0 # via virtualenv -pluggy==1.3.0 - # via pytest -py==1.11.0 +pluggy==1.5.0 # via pytest -pydantic==2.7.1 +pydantic==2.10.3 # via metronome-sdk -pydantic-core==2.18.2 +pydantic-core==2.27.1 # via pydantic pygments==2.18.0 # via rich -pyright==1.1.380 -pytest==7.1.1 +pyright==1.1.392.post0 +pytest==8.3.3 # via pytest-asyncio -pytest-asyncio==0.21.1 +pytest-asyncio==0.24.0 python-dateutil==2.8.2 # via time-machine pytz==2023.3.post1 # via dirty-equals -respx==0.20.2 +respx==0.22.0 rich==13.7.1 -ruff==0.6.5 +ruff==0.6.9 setuptools==68.2.2 # via nodeenv six==1.16.0 # via python-dateutil sniffio==1.3.0 # via anyio - # via httpx # via metronome-sdk time-machine==2.9.0 -tomli==2.0.1 +tomli==2.0.2 # via mypy # via pytest -typing-extensions==4.8.0 +typing-extensions==4.12.2 # via anyio # via metronome-sdk # via mypy # via pydantic # via pydantic-core + # via pyright virtualenv==20.24.5 # via nox zipp==3.17.0 diff --git a/requirements.lock b/requirements.lock index 3ab6afbc..375ef750 100644 --- a/requirements.lock +++ b/requirements.lock @@ -19,26 +19,25 @@ certifi==2023.7.22 # via httpx distro==1.8.0 # via metronome-sdk -exceptiongroup==1.1.3 +exceptiongroup==1.2.2 # via anyio h11==0.14.0 # via httpcore httpcore==1.0.2 # via httpx -httpx==0.25.2 +httpx==0.28.1 # via metronome-sdk idna==3.4 # via anyio # via httpx -pydantic==2.7.1 +pydantic==2.10.3 # via metronome-sdk -pydantic-core==2.18.2 +pydantic-core==2.27.1 # via pydantic sniffio==1.3.0 # via anyio - # via httpx # via metronome-sdk -typing-extensions==4.8.0 +typing-extensions==4.12.2 # via anyio # via metronome-sdk # via pydantic diff --git a/scripts/bootstrap b/scripts/bootstrap index 8c5c60eb..e84fe62c 100755 --- a/scripts/bootstrap +++ b/scripts/bootstrap @@ -4,7 +4,7 @@ set -e cd "$(dirname "$0")/.." -if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ]; then +if ! command -v rye >/dev/null 2>&1 && [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ]; then brew bundle check >/dev/null 2>&1 || { echo "==> Installing Homebrew dependencies…" brew bundle diff --git a/scripts/lint b/scripts/lint index 6e29414e..9718b00b 100755 --- a/scripts/lint +++ b/scripts/lint @@ -9,4 +9,3 @@ rye run lint echo "==> Making sure it imports" rye run python -c 'import metronome' - diff --git a/src/metronome/__init__.py b/src/metronome/__init__.py index cdac988a..0bcf62c3 100644 --- a/src/metronome/__init__.py +++ b/src/metronome/__init__.py @@ -1,7 +1,7 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. from . import types -from ._types import NOT_GIVEN, NoneType, NotGiven, Transport, ProxiesTypes +from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes from ._utils import file_from_path from ._client import ( Client, @@ -46,6 +46,7 @@ "ProxiesTypes", "NotGiven", "NOT_GIVEN", + "Omit", "MetronomeError", "APIError", "APIStatusError", diff --git a/src/metronome/_base_client.py b/src/metronome/_base_client.py index 6a157b40..b6ea919d 100644 --- a/src/metronome/_base_client.py +++ b/src/metronome/_base_client.py @@ -143,6 +143,12 @@ def __init__( self.url = url self.params = params + @override + def __repr__(self) -> str: + if self.url: + return f"{self.__class__.__name__}(url={self.url})" + return f"{self.__class__.__name__}(params={self.params})" + class BasePage(GenericModel, Generic[_T]): """ @@ -412,7 +418,10 @@ def _build_headers(self, options: FinalRequestOptions, *, retries_taken: int = 0 if idempotency_header and options.method.lower() != "get" and idempotency_header not in headers: headers[idempotency_header] = options.idempotency_key or self._idempotency_key() - headers.setdefault("x-stainless-retry-count", str(retries_taken)) + # Don't set the retry count header if it was already set or removed by the caller. We check + # `custom_headers`, which can contain `Omit()`, instead of `headers` to account for the removal case. + if "x-stainless-retry-count" not in (header.lower() for header in custom_headers): + headers["x-stainless-retry-count"] = str(retries_taken) return headers @@ -686,7 +695,8 @@ def _calculate_retry_timeout( if retry_after is not None and 0 < retry_after <= 60: return retry_after - nb_retries = max_retries - remaining_retries + # 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) @@ -757,6 +767,9 @@ def __init__(self, **kwargs: Any) -> None: class SyncHttpxClientWrapper(DefaultHttpxClient): def __del__(self) -> None: + if self.is_closed: + return + try: self.close() except Exception: @@ -782,6 +795,7 @@ def __init__( custom_query: Mapping[str, object] | None = None, _strict_response_validation: bool, ) -> None: + kwargs: dict[str, Any] = {} if limits is not None: warnings.warn( "The `connection_pool_limits` argument is deprecated. The `http_client` argument should be passed instead", @@ -794,6 +808,7 @@ def __init__( limits = DEFAULT_CONNECTION_LIMITS if transport is not None: + kwargs["transport"] = transport warnings.warn( "The `transport` argument is deprecated. The `http_client` argument should be passed instead", category=DeprecationWarning, @@ -803,6 +818,7 @@ def __init__( raise ValueError("The `http_client` argument is mutually exclusive with `transport`") if proxies is not None: + kwargs["proxies"] = proxies warnings.warn( "The `proxies` argument is deprecated. The `http_client` argument should be passed instead", category=DeprecationWarning, @@ -846,10 +862,9 @@ def __init__( base_url=base_url, # cast to a valid type because mypy doesn't understand our type narrowing timeout=cast(Timeout, timeout), - proxies=proxies, - transport=transport, limits=limits, follow_redirects=True, + **kwargs, # type: ignore ) def is_closed(self) -> bool: @@ -1322,6 +1337,9 @@ def __init__(self, **kwargs: Any) -> None: 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()) @@ -1348,6 +1366,7 @@ def __init__( custom_headers: Mapping[str, str] | None = None, custom_query: Mapping[str, object] | None = None, ) -> None: + kwargs: dict[str, Any] = {} if limits is not None: warnings.warn( "The `connection_pool_limits` argument is deprecated. The `http_client` argument should be passed instead", @@ -1360,6 +1379,7 @@ def __init__( limits = DEFAULT_CONNECTION_LIMITS if transport is not None: + kwargs["transport"] = transport warnings.warn( "The `transport` argument is deprecated. The `http_client` argument should be passed instead", category=DeprecationWarning, @@ -1369,6 +1389,7 @@ def __init__( raise ValueError("The `http_client` argument is mutually exclusive with `transport`") if proxies is not None: + kwargs["proxies"] = proxies warnings.warn( "The `proxies` argument is deprecated. The `http_client` argument should be passed instead", category=DeprecationWarning, @@ -1412,10 +1433,9 @@ def __init__( base_url=base_url, # cast to a valid type because mypy doesn't understand our type narrowing timeout=cast(Timeout, timeout), - proxies=proxies, - transport=transport, limits=limits, follow_redirects=True, + **kwargs, # type: ignore ) def is_closed(self) -> bool: @@ -1565,7 +1585,7 @@ async def _request( except Exception as err: log.debug("Encountered Exception", exc_info=True) - if retries_taken > 0: + if remaining_retries > 0: return await self._retry_request( input_options, cast_to, diff --git a/src/metronome/_client.py b/src/metronome/_client.py index f5049142..76986aa6 100644 --- a/src/metronome/_client.py +++ b/src/metronome/_client.py @@ -8,7 +8,7 @@ import httpx -from . import resources, _exceptions +from . import _exceptions from ._qs import Querystring from ._types import ( NOT_GIVEN, @@ -24,6 +24,18 @@ get_async_library, ) from ._version import __version__ +from .resources import ( + plans, + usage, + alerts, + invoices, + services, + audit_logs, + dashboards, + credit_grants, + custom_fields, + billable_metrics, +) from ._streaming import Stream as Stream, AsyncStream as AsyncStream from ._exceptions import APIStatusError, MetronomeError from ._base_client import ( @@ -31,13 +43,14 @@ SyncAPIClient, AsyncAPIClient, ) +from .resources.contracts import contracts +from .resources.customers import customers __all__ = [ "Timeout", "Transport", "ProxiesTypes", "RequestOptions", - "resources", "Metronome", "AsyncMetronome", "Client", @@ -46,18 +59,18 @@ class Metronome(SyncAPIClient): - alerts: resources.AlertsResource - plans: resources.PlansResource - credit_grants: resources.CreditGrantsResource - customers: resources.CustomersResource - dashboards: resources.DashboardsResource - usage: resources.UsageResource - audit_logs: resources.AuditLogsResource - custom_fields: resources.CustomFieldsResource - billable_metrics: resources.BillableMetricsResource - services: resources.ServicesResource - invoices: resources.InvoicesResource - contracts: resources.ContractsResource + alerts: alerts.AlertsResource + plans: plans.PlansResource + credit_grants: credit_grants.CreditGrantsResource + customers: customers.CustomersResource + dashboards: dashboards.DashboardsResource + usage: usage.UsageResource + audit_logs: audit_logs.AuditLogsResource + custom_fields: custom_fields.CustomFieldsResource + billable_metrics: billable_metrics.BillableMetricsResource + services: services.ServicesResource + invoices: invoices.InvoicesResource + contracts: contracts.ContractsResource with_raw_response: MetronomeWithRawResponse with_streaming_response: MetronomeWithStreamedResponse @@ -123,18 +136,18 @@ def __init__( _strict_response_validation=_strict_response_validation, ) - self.alerts = resources.AlertsResource(self) - self.plans = resources.PlansResource(self) - self.credit_grants = resources.CreditGrantsResource(self) - self.customers = resources.CustomersResource(self) - self.dashboards = resources.DashboardsResource(self) - self.usage = resources.UsageResource(self) - self.audit_logs = resources.AuditLogsResource(self) - self.custom_fields = resources.CustomFieldsResource(self) - self.billable_metrics = resources.BillableMetricsResource(self) - self.services = resources.ServicesResource(self) - self.invoices = resources.InvoicesResource(self) - self.contracts = resources.ContractsResource(self) + self.alerts = alerts.AlertsResource(self) + self.plans = plans.PlansResource(self) + self.credit_grants = credit_grants.CreditGrantsResource(self) + self.customers = customers.CustomersResource(self) + self.dashboards = dashboards.DashboardsResource(self) + self.usage = usage.UsageResource(self) + self.audit_logs = audit_logs.AuditLogsResource(self) + self.custom_fields = custom_fields.CustomFieldsResource(self) + self.billable_metrics = billable_metrics.BillableMetricsResource(self) + self.services = services.ServicesResource(self) + self.invoices = invoices.InvoicesResource(self) + self.contracts = contracts.ContractsResource(self) self.with_raw_response = MetronomeWithRawResponse(self) self.with_streaming_response = MetronomeWithStreamedResponse(self) @@ -246,18 +259,18 @@ def _make_status_error( class AsyncMetronome(AsyncAPIClient): - alerts: resources.AsyncAlertsResource - plans: resources.AsyncPlansResource - credit_grants: resources.AsyncCreditGrantsResource - customers: resources.AsyncCustomersResource - dashboards: resources.AsyncDashboardsResource - usage: resources.AsyncUsageResource - audit_logs: resources.AsyncAuditLogsResource - custom_fields: resources.AsyncCustomFieldsResource - billable_metrics: resources.AsyncBillableMetricsResource - services: resources.AsyncServicesResource - invoices: resources.AsyncInvoicesResource - contracts: resources.AsyncContractsResource + alerts: alerts.AsyncAlertsResource + plans: plans.AsyncPlansResource + credit_grants: credit_grants.AsyncCreditGrantsResource + customers: customers.AsyncCustomersResource + dashboards: dashboards.AsyncDashboardsResource + usage: usage.AsyncUsageResource + audit_logs: audit_logs.AsyncAuditLogsResource + custom_fields: custom_fields.AsyncCustomFieldsResource + billable_metrics: billable_metrics.AsyncBillableMetricsResource + services: services.AsyncServicesResource + invoices: invoices.AsyncInvoicesResource + contracts: contracts.AsyncContractsResource with_raw_response: AsyncMetronomeWithRawResponse with_streaming_response: AsyncMetronomeWithStreamedResponse @@ -323,18 +336,18 @@ def __init__( _strict_response_validation=_strict_response_validation, ) - self.alerts = resources.AsyncAlertsResource(self) - self.plans = resources.AsyncPlansResource(self) - self.credit_grants = resources.AsyncCreditGrantsResource(self) - self.customers = resources.AsyncCustomersResource(self) - self.dashboards = resources.AsyncDashboardsResource(self) - self.usage = resources.AsyncUsageResource(self) - self.audit_logs = resources.AsyncAuditLogsResource(self) - self.custom_fields = resources.AsyncCustomFieldsResource(self) - self.billable_metrics = resources.AsyncBillableMetricsResource(self) - self.services = resources.AsyncServicesResource(self) - self.invoices = resources.AsyncInvoicesResource(self) - self.contracts = resources.AsyncContractsResource(self) + self.alerts = alerts.AsyncAlertsResource(self) + self.plans = plans.AsyncPlansResource(self) + self.credit_grants = credit_grants.AsyncCreditGrantsResource(self) + self.customers = customers.AsyncCustomersResource(self) + self.dashboards = dashboards.AsyncDashboardsResource(self) + self.usage = usage.AsyncUsageResource(self) + self.audit_logs = audit_logs.AsyncAuditLogsResource(self) + self.custom_fields = custom_fields.AsyncCustomFieldsResource(self) + self.billable_metrics = billable_metrics.AsyncBillableMetricsResource(self) + self.services = services.AsyncServicesResource(self) + self.invoices = invoices.AsyncInvoicesResource(self) + self.contracts = contracts.AsyncContractsResource(self) self.with_raw_response = AsyncMetronomeWithRawResponse(self) self.with_streaming_response = AsyncMetronomeWithStreamedResponse(self) @@ -447,66 +460,68 @@ def _make_status_error( class MetronomeWithRawResponse: def __init__(self, client: Metronome) -> None: - self.alerts = resources.AlertsResourceWithRawResponse(client.alerts) - self.plans = resources.PlansResourceWithRawResponse(client.plans) - self.credit_grants = resources.CreditGrantsResourceWithRawResponse(client.credit_grants) - self.customers = resources.CustomersResourceWithRawResponse(client.customers) - self.dashboards = resources.DashboardsResourceWithRawResponse(client.dashboards) - self.usage = resources.UsageResourceWithRawResponse(client.usage) - self.audit_logs = resources.AuditLogsResourceWithRawResponse(client.audit_logs) - self.custom_fields = resources.CustomFieldsResourceWithRawResponse(client.custom_fields) - self.billable_metrics = resources.BillableMetricsResourceWithRawResponse(client.billable_metrics) - self.services = resources.ServicesResourceWithRawResponse(client.services) - self.invoices = resources.InvoicesResourceWithRawResponse(client.invoices) - self.contracts = resources.ContractsResourceWithRawResponse(client.contracts) + self.alerts = alerts.AlertsResourceWithRawResponse(client.alerts) + self.plans = plans.PlansResourceWithRawResponse(client.plans) + self.credit_grants = credit_grants.CreditGrantsResourceWithRawResponse(client.credit_grants) + self.customers = customers.CustomersResourceWithRawResponse(client.customers) + self.dashboards = dashboards.DashboardsResourceWithRawResponse(client.dashboards) + self.usage = usage.UsageResourceWithRawResponse(client.usage) + self.audit_logs = audit_logs.AuditLogsResourceWithRawResponse(client.audit_logs) + self.custom_fields = custom_fields.CustomFieldsResourceWithRawResponse(client.custom_fields) + self.billable_metrics = billable_metrics.BillableMetricsResourceWithRawResponse(client.billable_metrics) + self.services = services.ServicesResourceWithRawResponse(client.services) + self.invoices = invoices.InvoicesResourceWithRawResponse(client.invoices) + self.contracts = contracts.ContractsResourceWithRawResponse(client.contracts) class AsyncMetronomeWithRawResponse: def __init__(self, client: AsyncMetronome) -> None: - self.alerts = resources.AsyncAlertsResourceWithRawResponse(client.alerts) - self.plans = resources.AsyncPlansResourceWithRawResponse(client.plans) - self.credit_grants = resources.AsyncCreditGrantsResourceWithRawResponse(client.credit_grants) - self.customers = resources.AsyncCustomersResourceWithRawResponse(client.customers) - self.dashboards = resources.AsyncDashboardsResourceWithRawResponse(client.dashboards) - self.usage = resources.AsyncUsageResourceWithRawResponse(client.usage) - self.audit_logs = resources.AsyncAuditLogsResourceWithRawResponse(client.audit_logs) - self.custom_fields = resources.AsyncCustomFieldsResourceWithRawResponse(client.custom_fields) - self.billable_metrics = resources.AsyncBillableMetricsResourceWithRawResponse(client.billable_metrics) - self.services = resources.AsyncServicesResourceWithRawResponse(client.services) - self.invoices = resources.AsyncInvoicesResourceWithRawResponse(client.invoices) - self.contracts = resources.AsyncContractsResourceWithRawResponse(client.contracts) + self.alerts = alerts.AsyncAlertsResourceWithRawResponse(client.alerts) + self.plans = plans.AsyncPlansResourceWithRawResponse(client.plans) + self.credit_grants = credit_grants.AsyncCreditGrantsResourceWithRawResponse(client.credit_grants) + self.customers = customers.AsyncCustomersResourceWithRawResponse(client.customers) + self.dashboards = dashboards.AsyncDashboardsResourceWithRawResponse(client.dashboards) + self.usage = usage.AsyncUsageResourceWithRawResponse(client.usage) + self.audit_logs = audit_logs.AsyncAuditLogsResourceWithRawResponse(client.audit_logs) + self.custom_fields = custom_fields.AsyncCustomFieldsResourceWithRawResponse(client.custom_fields) + self.billable_metrics = billable_metrics.AsyncBillableMetricsResourceWithRawResponse(client.billable_metrics) + self.services = services.AsyncServicesResourceWithRawResponse(client.services) + self.invoices = invoices.AsyncInvoicesResourceWithRawResponse(client.invoices) + self.contracts = contracts.AsyncContractsResourceWithRawResponse(client.contracts) class MetronomeWithStreamedResponse: def __init__(self, client: Metronome) -> None: - self.alerts = resources.AlertsResourceWithStreamingResponse(client.alerts) - self.plans = resources.PlansResourceWithStreamingResponse(client.plans) - self.credit_grants = resources.CreditGrantsResourceWithStreamingResponse(client.credit_grants) - self.customers = resources.CustomersResourceWithStreamingResponse(client.customers) - self.dashboards = resources.DashboardsResourceWithStreamingResponse(client.dashboards) - self.usage = resources.UsageResourceWithStreamingResponse(client.usage) - self.audit_logs = resources.AuditLogsResourceWithStreamingResponse(client.audit_logs) - self.custom_fields = resources.CustomFieldsResourceWithStreamingResponse(client.custom_fields) - self.billable_metrics = resources.BillableMetricsResourceWithStreamingResponse(client.billable_metrics) - self.services = resources.ServicesResourceWithStreamingResponse(client.services) - self.invoices = resources.InvoicesResourceWithStreamingResponse(client.invoices) - self.contracts = resources.ContractsResourceWithStreamingResponse(client.contracts) + self.alerts = alerts.AlertsResourceWithStreamingResponse(client.alerts) + self.plans = plans.PlansResourceWithStreamingResponse(client.plans) + self.credit_grants = credit_grants.CreditGrantsResourceWithStreamingResponse(client.credit_grants) + self.customers = customers.CustomersResourceWithStreamingResponse(client.customers) + self.dashboards = dashboards.DashboardsResourceWithStreamingResponse(client.dashboards) + self.usage = usage.UsageResourceWithStreamingResponse(client.usage) + self.audit_logs = audit_logs.AuditLogsResourceWithStreamingResponse(client.audit_logs) + self.custom_fields = custom_fields.CustomFieldsResourceWithStreamingResponse(client.custom_fields) + self.billable_metrics = billable_metrics.BillableMetricsResourceWithStreamingResponse(client.billable_metrics) + self.services = services.ServicesResourceWithStreamingResponse(client.services) + self.invoices = invoices.InvoicesResourceWithStreamingResponse(client.invoices) + self.contracts = contracts.ContractsResourceWithStreamingResponse(client.contracts) class AsyncMetronomeWithStreamedResponse: def __init__(self, client: AsyncMetronome) -> None: - self.alerts = resources.AsyncAlertsResourceWithStreamingResponse(client.alerts) - self.plans = resources.AsyncPlansResourceWithStreamingResponse(client.plans) - self.credit_grants = resources.AsyncCreditGrantsResourceWithStreamingResponse(client.credit_grants) - self.customers = resources.AsyncCustomersResourceWithStreamingResponse(client.customers) - self.dashboards = resources.AsyncDashboardsResourceWithStreamingResponse(client.dashboards) - self.usage = resources.AsyncUsageResourceWithStreamingResponse(client.usage) - self.audit_logs = resources.AsyncAuditLogsResourceWithStreamingResponse(client.audit_logs) - self.custom_fields = resources.AsyncCustomFieldsResourceWithStreamingResponse(client.custom_fields) - self.billable_metrics = resources.AsyncBillableMetricsResourceWithStreamingResponse(client.billable_metrics) - self.services = resources.AsyncServicesResourceWithStreamingResponse(client.services) - self.invoices = resources.AsyncInvoicesResourceWithStreamingResponse(client.invoices) - self.contracts = resources.AsyncContractsResourceWithStreamingResponse(client.contracts) + self.alerts = alerts.AsyncAlertsResourceWithStreamingResponse(client.alerts) + self.plans = plans.AsyncPlansResourceWithStreamingResponse(client.plans) + self.credit_grants = credit_grants.AsyncCreditGrantsResourceWithStreamingResponse(client.credit_grants) + self.customers = customers.AsyncCustomersResourceWithStreamingResponse(client.customers) + self.dashboards = dashboards.AsyncDashboardsResourceWithStreamingResponse(client.dashboards) + self.usage = usage.AsyncUsageResourceWithStreamingResponse(client.usage) + self.audit_logs = audit_logs.AsyncAuditLogsResourceWithStreamingResponse(client.audit_logs) + self.custom_fields = custom_fields.AsyncCustomFieldsResourceWithStreamingResponse(client.custom_fields) + self.billable_metrics = billable_metrics.AsyncBillableMetricsResourceWithStreamingResponse( + client.billable_metrics + ) + self.services = services.AsyncServicesResourceWithStreamingResponse(client.services) + self.invoices = invoices.AsyncInvoicesResourceWithStreamingResponse(client.invoices) + self.contracts = contracts.AsyncContractsResourceWithStreamingResponse(client.contracts) Client = Metronome diff --git a/src/metronome/_compat.py b/src/metronome/_compat.py index 21fe6941..92d9ee61 100644 --- a/src/metronome/_compat.py +++ b/src/metronome/_compat.py @@ -2,7 +2,7 @@ from typing import TYPE_CHECKING, Any, Union, Generic, TypeVar, Callable, cast, overload from datetime import date, datetime -from typing_extensions import Self +from typing_extensions import Self, Literal import pydantic from pydantic.fields import FieldInfo @@ -133,15 +133,20 @@ def model_json(model: pydantic.BaseModel, *, indent: int | None = None) -> str: def model_dump( model: pydantic.BaseModel, *, - exclude: IncEx = None, + exclude: IncEx | None = None, exclude_unset: bool = False, exclude_defaults: bool = False, + warnings: bool = True, + mode: Literal["json", "python"] = "python", ) -> dict[str, Any]: - if PYDANTIC_V2: + if PYDANTIC_V2 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=warnings if PYDANTIC_V2 else True, ) return cast( "dict[str, Any]", @@ -209,9 +214,6 @@ 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: - try: - from functools import cached_property as cached_property - except ImportError: - from cached_property import cached_property as cached_property + from functools import cached_property as cached_property typed_cached_property = cached_property diff --git a/src/metronome/_models.py b/src/metronome/_models.py index d386eaa3..9a918aab 100644 --- a/src/metronome/_models.py +++ b/src/metronome/_models.py @@ -37,6 +37,7 @@ PropertyInfo, is_list, is_given, + json_safe, lru_cache, is_mapping, parse_date, @@ -45,6 +46,7 @@ strip_not_given, extract_type_arg, is_annotated_type, + is_type_alias_type, strip_annotated_type, ) from ._compat import ( @@ -176,15 +178,15 @@ def __str__(self) -> str: # Based on https://github.com/samuelcolvin/pydantic/issues/1168#issuecomment-817742836. @classmethod @override - def construct( - cls: Type[ModelT], + def construct( # pyright: ignore[reportIncompatibleMethodOverride] + __cls: Type[ModelT], _fields_set: set[str] | None = None, **values: object, ) -> ModelT: - m = cls.__new__(cls) + m = __cls.__new__(__cls) fields_values: dict[str, object] = {} - config = get_model_config(cls) + config = get_model_config(__cls) populate_by_name = ( config.allow_population_by_field_name if isinstance(config, _ConfigProtocol) @@ -194,7 +196,7 @@ def construct( if _fields_set is None: _fields_set = set() - model_fields = get_model_fields(cls) + 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): @@ -248,8 +250,8 @@ def model_dump( self, *, mode: Literal["json", "python"] | str = "python", - include: IncEx = None, - exclude: IncEx = None, + include: IncEx | None = None, + exclude: IncEx | None = None, by_alias: bool = False, exclude_unset: bool = False, exclude_defaults: bool = False, @@ -279,8 +281,8 @@ def model_dump( Returns: A dictionary representation of the model. """ - if mode != "python": - raise ValueError("mode is only supported in Pydantic v2") + 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: @@ -289,7 +291,7 @@ def model_dump( 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") - return super().dict( # pyright: ignore[reportDeprecated] + dumped = super().dict( # pyright: ignore[reportDeprecated] include=include, exclude=exclude, by_alias=by_alias, @@ -298,13 +300,15 @@ def model_dump( 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, - include: IncEx = None, - exclude: IncEx = None, + include: IncEx | None = None, + exclude: IncEx | None = None, by_alias: bool = False, exclude_unset: bool = False, exclude_defaults: bool = False, @@ -425,6 +429,8 @@ def construct_type(*, value: object, type_: object) -> object: # 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_): + type_ = type_.__value__ # type: ignore[unreachable] # unwrap `Annotated[T, ...]` -> `T` if is_annotated_type(type_): @@ -482,7 +488,11 @@ def construct_type(*, value: object, type_: object) -> object: _, 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 (issubclass(origin, BaseModel) or issubclass(origin, GenericModel)): + 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] diff --git a/src/metronome/_response.py b/src/metronome/_response.py index 21aa7ce7..826bb4b3 100644 --- a/src/metronome/_response.py +++ b/src/metronome/_response.py @@ -25,7 +25,7 @@ import pydantic from ._types import NoneType -from ._utils import is_given, extract_type_arg, is_annotated_type, extract_type_var_from_base +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 @@ -126,9 +126,17 @@ def __repr__(self) -> str: ) 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 to and is_annotated_type(to): - to = extract_type_arg(to, 0) + 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: @@ -164,18 +172,12 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: return cast( R, stream_cls( - cast_to=self._cast_to, + cast_to=cast_to, response=self.http_response, client=cast(Any, self._client), ), ) - cast_to = to if to is not None else self._cast_to - - # unwrap `Annotated[T, ...]` -> `T` - if is_annotated_type(cast_to): - cast_to = extract_type_arg(cast_to, 0) - if cast_to is NoneType: return cast(R, None) @@ -192,7 +194,8 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: if cast_to == float: return cast(R, float(response.text)) - origin = get_origin(cast_to) or cast_to + if cast_to == bool: + return cast(R, response.text.lower() == "true") if origin == APIResponse: raise RuntimeError("Unexpected state - cast_to is `APIResponse`") @@ -207,7 +210,13 @@ def _parse(self, *, to: type[_T] | None = None) -> R | _T: raise ValueError(f"Subclasses of httpx.Response cannot be passed to `cast_to`") return cast(R, response) - if inspect.isclass(origin) and not issubclass(origin, BaseModel) and issubclass(origin, pydantic.BaseModel): + 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 ( diff --git a/src/metronome/_types.py b/src/metronome/_types.py index fb96a5a0..07042e44 100644 --- a/src/metronome/_types.py +++ b/src/metronome/_types.py @@ -16,7 +16,7 @@ Optional, Sequence, ) -from typing_extensions import Literal, Protocol, TypeAlias, TypedDict, override, runtime_checkable +from typing_extensions import Set, Literal, Protocol, TypeAlias, TypedDict, override, runtime_checkable import httpx import pydantic @@ -192,8 +192,8 @@ def get(self, __key: str) -> str | None: ... StrBytesIntFloat = Union[str, bytes, int, float] # Note: copied from Pydantic -# https://github.com/pydantic/pydantic/blob/32ea570bf96e84234d2992e1ddf40ab8a565925a/pydantic/main.py#L49 -IncEx: TypeAlias = "set[int] | set[str] | dict[int, Any] | dict[str, Any] | None" +# 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] diff --git a/src/metronome/_utils/__init__.py b/src/metronome/_utils/__init__.py index 3efe66c8..d4fda26f 100644 --- a/src/metronome/_utils/__init__.py +++ b/src/metronome/_utils/__init__.py @@ -6,6 +6,7 @@ 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, @@ -38,6 +39,7 @@ is_iterable_type as is_iterable_type, is_required_type as is_required_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, ) diff --git a/src/metronome/_utils/_sync.py b/src/metronome/_utils/_sync.py index d0d81033..8b3aaf2b 100644 --- a/src/metronome/_utils/_sync.py +++ b/src/metronome/_utils/_sync.py @@ -1,56 +1,62 @@ from __future__ import annotations +import sys +import asyncio import functools -from typing import TypeVar, Callable, Awaitable +import contextvars +from typing import Any, TypeVar, Callable, Awaitable from typing_extensions import ParamSpec -import anyio -import anyio.to_thread - -from ._reflection import function_has_argument - T_Retval = TypeVar("T_Retval") T_ParamSpec = ParamSpec("T_ParamSpec") -# copied from `asyncer`, https://github.com/tiangolo/asyncer -def asyncify( - function: Callable[T_ParamSpec, T_Retval], - *, - cancellable: bool = False, - limiter: anyio.CapacityLimiter | None = None, -) -> Callable[T_ParamSpec, Awaitable[T_Retval]]: +if sys.version_info >= (3, 9): + to_thread = asyncio.to_thread +else: + # backport of https://docs.python.org/3/library/asyncio-task.html#asyncio.to_thread + # for Python 3.8 support + async def to_thread( + func: Callable[T_ParamSpec, T_Retval], /, *args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs + ) -> Any: + """Asynchronously run function *func* in a separate thread. + + Any *args and **kwargs supplied for this function are directly passed + to *func*. Also, the current :class:`contextvars.Context` is propagated, + allowing context variables from the main thread to be accessed in the + separate thread. + + Returns a coroutine that can be awaited to get the eventual result of *func*. + """ + loop = asyncio.events.get_running_loop() + ctx = contextvars.copy_context() + func_call = functools.partial(ctx.run, func, *args, **kwargs) + return await loop.run_in_executor(None, func_call) + + +# 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, and that when called, calls the original function - in a worker thread using `anyio.to_thread.run_sync()`. Internally, - `asyncer.asyncify()` uses the same `anyio.to_thread.run_sync()`, but it supports - keyword arguments additional to positional arguments and it adds better support for - autocompletion and inline errors for the arguments of the function called and the - return value. - - If the `cancellable` option is enabled and the task waiting for its completion is - cancelled, the thread will still run its course but its return value (or any raised - exception) will be ignored. + positional and keyword arguments. For python version 3.9 and above, it uses + asyncio.to_thread to run the function in a separate thread. For python version + 3.8, it uses locally defined copy of the asyncio.to_thread function which was + introduced in python 3.9. - Use it like this: + Usage: - ```Python - def do_work(arg1, arg2, kwarg1="", kwarg2="") -> str: - # Do work - return "Some result" + ```python + def blocking_func(arg1, arg2, kwarg1=None): + # blocking code + return result - result = await to_thread.asyncify(do_work)("spam", "ham", kwarg1="a", kwarg2="b") - print(result) + result = asyncify(blocking_function)(arg1, arg2, kwarg1=value1) ``` ## Arguments `function`: a blocking regular callable (e.g. a function) - `cancellable`: `True` to allow cancellation of the operation - `limiter`: capacity limiter to use to limit the total amount of threads running - (if omitted, the default limiter is used) ## Return @@ -60,22 +66,6 @@ def do_work(arg1, arg2, kwarg1="", kwarg2="") -> str: """ async def wrapper(*args: T_ParamSpec.args, **kwargs: T_ParamSpec.kwargs) -> T_Retval: - partial_f = functools.partial(function, *args, **kwargs) - - # In `v4.1.0` anyio added the `abandon_on_cancel` argument and deprecated the old - # `cancellable` argument, so we need to use the new `abandon_on_cancel` to avoid - # surfacing deprecation warnings. - if function_has_argument(anyio.to_thread.run_sync, "abandon_on_cancel"): - return await anyio.to_thread.run_sync( - partial_f, - abandon_on_cancel=cancellable, - limiter=limiter, - ) - - return await anyio.to_thread.run_sync( - partial_f, - cancellable=cancellable, - limiter=limiter, - ) + return await to_thread(function, *args, **kwargs) return wrapper diff --git a/src/metronome/_utils/_transform.py b/src/metronome/_utils/_transform.py index 47e262a5..a6b62cad 100644 --- a/src/metronome/_utils/_transform.py +++ b/src/metronome/_utils/_transform.py @@ -173,6 +173,11 @@ def _transform_recursive( # Iterable[T] or (is_iterable_type(stripped_type) and is_iterable(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) return [_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data] @@ -186,7 +191,7 @@ def _transform_recursive( return data if isinstance(data, pydantic.BaseModel): - return model_dump(data, exclude_unset=True) + return model_dump(data, exclude_unset=True, mode="json") annotated_type = _get_annotated_type(annotation) if annotated_type is None: @@ -311,6 +316,11 @@ async def _async_transform_recursive( # Iterable[T] or (is_iterable_type(stripped_type) and is_iterable(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) return [await _async_transform_recursive(d, annotation=annotation, inner_type=inner_type) for d in data] @@ -324,7 +334,7 @@ async def _async_transform_recursive( return data if isinstance(data, pydantic.BaseModel): - return model_dump(data, exclude_unset=True) + return model_dump(data, exclude_unset=True, mode="json") annotated_type = _get_annotated_type(annotation) if annotated_type is None: diff --git a/src/metronome/_utils/_typing.py b/src/metronome/_utils/_typing.py index c036991f..278749b1 100644 --- a/src/metronome/_utils/_typing.py +++ b/src/metronome/_utils/_typing.py @@ -1,8 +1,17 @@ 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 Required, Annotated, get_args, get_origin +from typing_extensions import ( + TypeIs, + Required, + Annotated, + get_args, + get_origin, +) from .._types import InheritsGeneric from .._compat import is_union as _is_union @@ -36,6 +45,26 @@ def is_typevar(typ: type) -> bool: 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, ...]] def strip_annotated_type(typ: type) -> type: if is_required_type(typ) or is_annotated_type(typ): diff --git a/src/metronome/_utils/_utils.py b/src/metronome/_utils/_utils.py index 0bba17ca..e5811bba 100644 --- a/src/metronome/_utils/_utils.py +++ b/src/metronome/_utils/_utils.py @@ -16,6 +16,7 @@ overload, ) from pathlib import Path +from datetime import date, datetime from typing_extensions import TypeGuard import sniffio @@ -395,3 +396,19 @@ def lru_cache(*, maxsize: int | None = 128) -> Callable[[CallableT], CallableT]: 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() + + return data diff --git a/src/metronome/_version.py b/src/metronome/_version.py index 7c1be839..52c3dbf2 100644 --- a/src/metronome/_version.py +++ b/src/metronome/_version.py @@ -1,4 +1,4 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. __title__ = "metronome" -__version__ = "0.1.0-beta.3" # x-release-please-version +__version__ = "0.1.0-beta.4" # x-release-please-version diff --git a/src/metronome/resources/alerts.py b/src/metronome/resources/alerts.py index d45b8cfc..64dcefc4 100644 --- a/src/metronome/resources/alerts.py +++ b/src/metronome/resources/alerts.py @@ -32,7 +32,7 @@ class AlertsResource(SyncAPIResource): @cached_property def with_raw_response(self) -> AlertsResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -94,7 +94,8 @@ def create( name: Name of the alert - threshold: Threshold value of the alert policy + threshold: Threshold value of the alert policy. Depending upon the alert type, this number + may represent a financial amount, the days remaining, or a percentage reached. billable_metric_id: For alerts of type `usage_threshold_reached`, specifies which billable metric to track the usage for. @@ -165,6 +166,7 @@ def archive( self, *, id: str, + release_uniqueness_key: bool | NotGiven = NOT_GIVEN, # 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, @@ -176,6 +178,10 @@ def archive( Archive an existing alert Args: + id: The Metronome ID of the alert + + release_uniqueness_key: If true, resets the uniqueness key on this alert so it can be re-used + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -186,7 +192,13 @@ def archive( """ return self._post( "/alerts/archive", - body=maybe_transform({"id": id}, alert_archive_params.AlertArchiveParams), + 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 ), @@ -198,7 +210,7 @@ class AsyncAlertsResource(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncAlertsResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -260,7 +272,8 @@ async def create( name: Name of the alert - threshold: Threshold value of the alert policy + threshold: Threshold value of the alert policy. Depending upon the alert type, this number + may represent a financial amount, the days remaining, or a percentage reached. billable_metric_id: For alerts of type `usage_threshold_reached`, specifies which billable metric to track the usage for. @@ -331,6 +344,7 @@ async def archive( self, *, id: str, + release_uniqueness_key: bool | NotGiven = NOT_GIVEN, # 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, @@ -342,6 +356,10 @@ async def archive( Archive an existing alert Args: + id: The Metronome ID of the alert + + release_uniqueness_key: If true, resets the uniqueness key on this alert so it can be re-used + extra_headers: Send extra headers extra_query: Add additional query parameters to the request @@ -352,7 +370,13 @@ async def archive( """ return await self._post( "/alerts/archive", - body=await async_maybe_transform({"id": id}, alert_archive_params.AlertArchiveParams), + 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 ), diff --git a/src/metronome/resources/audit_logs.py b/src/metronome/resources/audit_logs.py index 9362551b..f9a3481a 100644 --- a/src/metronome/resources/audit_logs.py +++ b/src/metronome/resources/audit_logs.py @@ -30,7 +30,7 @@ class AuditLogsResource(SyncAPIResource): @cached_property def with_raw_response(self) -> AuditLogsResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -125,7 +125,7 @@ class AsyncAuditLogsResource(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncAuditLogsResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 diff --git a/src/metronome/resources/billable_metrics.py b/src/metronome/resources/billable_metrics.py index 0b337a18..1735fa0a 100644 --- a/src/metronome/resources/billable_metrics.py +++ b/src/metronome/resources/billable_metrics.py @@ -41,7 +41,7 @@ class BillableMetricsResource(SyncAPIResource): @cached_property def with_raw_response(self) -> BillableMetricsResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -60,13 +60,14 @@ def with_streaming_response(self) -> BillableMetricsResourceWithStreamingRespons def create( self, *, - aggregation_type: Literal["COUNT", "LATEST", "MAX", "SUM", "UNIQUE"], name: str, aggregation_key: str | NotGiven = NOT_GIVEN, + aggregation_type: Literal["COUNT", "LATEST", "MAX", "SUM", "UNIQUE"] | NotGiven = NOT_GIVEN, custom_fields: Dict[str, str] | NotGiven = NOT_GIVEN, event_type_filter: EventTypeFilter | NotGiven = NOT_GIVEN, group_keys: Iterable[List[str]] | NotGiven = NOT_GIVEN, property_filters: Iterable[PropertyFilter] | NotGiven = NOT_GIVEN, + sql: str | NotGiven = NOT_GIVEN, # 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, @@ -78,13 +79,12 @@ def create( Creates a new Billable Metric. Args: - aggregation_type: Specifies the type of aggregation performed on matching events. - name: The display name of the billable metric. - aggregation_key: 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_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. @@ -97,6 +97,11 @@ def create( 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 @@ -109,13 +114,14 @@ def create( "/billable-metrics/create", body=maybe_transform( { - "aggregation_type": aggregation_type, "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, ), @@ -127,8 +133,8 @@ def create( def retrieve( self, - billable_metric_id: str, *, + 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, @@ -161,6 +167,7 @@ def retrieve( def list( self, *, + include_archived: bool | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, next_page: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -174,6 +181,8 @@ def list( List all billable metrics. 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. @@ -196,6 +205,7 @@ def list( timeout=timeout, query=maybe_transform( { + "include_archived": include_archived, "limit": limit, "next_page": next_page, }, @@ -242,7 +252,7 @@ class AsyncBillableMetricsResource(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncBillableMetricsResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -261,13 +271,14 @@ def with_streaming_response(self) -> AsyncBillableMetricsResourceWithStreamingRe async def create( self, *, - aggregation_type: Literal["COUNT", "LATEST", "MAX", "SUM", "UNIQUE"], name: str, aggregation_key: str | NotGiven = NOT_GIVEN, + aggregation_type: Literal["COUNT", "LATEST", "MAX", "SUM", "UNIQUE"] | NotGiven = NOT_GIVEN, custom_fields: Dict[str, str] | NotGiven = NOT_GIVEN, event_type_filter: EventTypeFilter | NotGiven = NOT_GIVEN, group_keys: Iterable[List[str]] | NotGiven = NOT_GIVEN, property_filters: Iterable[PropertyFilter] | NotGiven = NOT_GIVEN, + sql: str | NotGiven = NOT_GIVEN, # 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, @@ -279,13 +290,12 @@ async def create( Creates a new Billable Metric. Args: - aggregation_type: Specifies the type of aggregation performed on matching events. - name: The display name of the billable metric. - aggregation_key: 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_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. @@ -298,6 +308,11 @@ async def create( 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 @@ -310,13 +325,14 @@ async def create( "/billable-metrics/create", body=await async_maybe_transform( { - "aggregation_type": aggregation_type, "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, ), @@ -328,8 +344,8 @@ async def create( async def retrieve( self, - billable_metric_id: str, *, + 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, @@ -362,6 +378,7 @@ async def retrieve( def list( self, *, + include_archived: bool | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, next_page: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -375,6 +392,8 @@ def list( List all billable metrics. 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. @@ -397,6 +416,7 @@ def list( timeout=timeout, query=maybe_transform( { + "include_archived": include_archived, "limit": limit, "next_page": next_page, }, diff --git a/src/metronome/resources/contracts/contracts.py b/src/metronome/resources/contracts/contracts.py index 6869b618..208f538a 100644 --- a/src/metronome/resources/contracts/contracts.py +++ b/src/metronome/resources/contracts/contracts.py @@ -36,14 +36,6 @@ AsyncProductsResourceWithStreamingResponse, ) from ..._compat import cached_property -from .rate_cards import ( - RateCardsResource, - AsyncRateCardsResource, - RateCardsResourceWithRawResponse, - AsyncRateCardsResourceWithRawResponse, - RateCardsResourceWithStreamingResponse, - AsyncRateCardsResourceWithStreamingResponse, -) from ..._resource import SyncAPIResource, AsyncAPIResource from ..._response import ( to_raw_response_wrapper, @@ -60,7 +52,14 @@ NamedSchedulesResourceWithStreamingResponse, AsyncNamedSchedulesResourceWithStreamingResponse, ) -from .rate_cards.rate_cards import RateCardsResource, AsyncRateCardsResource +from .rate_cards.rate_cards import ( + RateCardsResource, + AsyncRateCardsResource, + RateCardsResourceWithRawResponse, + AsyncRateCardsResourceWithRawResponse, + RateCardsResourceWithStreamingResponse, + AsyncRateCardsResourceWithStreamingResponse, +) from ...types.contract_list_response import ContractListResponse from ...types.contract_amend_response import ContractAmendResponse from ...types.contract_create_response import ContractCreateResponse @@ -92,7 +91,7 @@ def named_schedules(self) -> NamedSchedulesResource: @cached_property def with_raw_response(self) -> ContractsResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -130,6 +129,7 @@ def create( reseller_royalties: Iterable[contract_create_params.ResellerRoyalty] | NotGiven = NOT_GIVEN, salesforce_opportunity_id: str | NotGiven = NOT_GIVEN, scheduled_charges: Iterable[contract_create_params.ScheduledCharge] | NotGiven = NOT_GIVEN, + scheduled_charges_on_usage_invoices: Literal["ALL"] | NotGiven = NOT_GIVEN, total_contract_value: float | NotGiven = NOT_GIVEN, transition: contract_create_params.Transition | NotGiven = NOT_GIVEN, uniqueness_key: str | NotGiven = NOT_GIVEN, @@ -148,7 +148,7 @@ def create( Args: starting_at: inclusive contract start time - billing_provider_configuration: This field's availability is dependent on your client's configuration. + billing_provider_configuration: The billing provider configuration associated with a contract. discounts: This field's availability is dependent on your client's configuration. @@ -170,6 +170,12 @@ def create( 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. + 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 @@ -207,6 +213,7 @@ def create( "reseller_royalties": reseller_royalties, "salesforce_opportunity_id": salesforce_opportunity_id, "scheduled_charges": scheduled_charges, + "scheduled_charges_on_usage_invoices": scheduled_charges_on_usage_invoices, "total_contract_value": total_contract_value, "transition": transition, "uniqueness_key": uniqueness_key, @@ -226,6 +233,7 @@ def retrieve( *, contract_id: str, customer_id: str, + include_balance: bool | NotGiven = NOT_GIVEN, include_ledgers: bool | NotGiven = NOT_GIVEN, # 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. @@ -238,6 +246,9 @@ def retrieve( Get a specific contract 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. @@ -255,6 +266,7 @@ def retrieve( { "contract_id": contract_id, "customer_id": customer_id, + "include_balance": include_balance, "include_ledgers": include_ledgers, }, contract_retrieve_params.ContractRetrieveParams, @@ -271,6 +283,7 @@ def list( customer_id: str, covering_date: Union[str, datetime] | NotGiven = NOT_GIVEN, include_archived: bool | NotGiven = NOT_GIVEN, + include_balance: bool | NotGiven = NOT_GIVEN, include_ledgers: bool | NotGiven = NOT_GIVEN, starting_at: Union[str, datetime] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -290,6 +303,9 @@ def list( 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. @@ -312,6 +328,7 @@ def list( "customer_id": customer_id, "covering_date": covering_date, "include_archived": include_archived, + "include_balance": include_balance, "include_ledgers": include_ledgers, "starting_at": starting_at, }, @@ -564,6 +581,7 @@ def list_balances( covering_date: Union[str, datetime] | NotGiven = NOT_GIVEN, effective_before: Union[str, datetime] | NotGiven = NOT_GIVEN, include_archived: bool | NotGiven = NOT_GIVEN, + include_balance: bool | NotGiven = NOT_GIVEN, include_contract_balances: bool | NotGiven = NOT_GIVEN, include_ledgers: bool | NotGiven = NOT_GIVEN, next_page: str | NotGiven = NOT_GIVEN, @@ -585,6 +603,9 @@ def list_balances( include_archived: Include 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 @@ -611,6 +632,7 @@ def list_balances( "covering_date": covering_date, "effective_before": effective_before, "include_archived": include_archived, + "include_balance": include_balance, "include_contract_balances": include_contract_balances, "include_ledgers": include_ledgers, "next_page": next_page, @@ -710,7 +732,7 @@ def schedule_pro_services_invoice( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> ContractScheduleProServicesInvoiceResponse: """ - Create a new, scheduled invoice for Professional Services terms on a contract. + Create a new scheduled invoice for Professional Services terms on a contract. This endpoint's availability is dependent on your client's configuration. Args: @@ -800,6 +822,7 @@ def update_end_date( *, contract_id: str, customer_id: str, + allow_ending_before_finalized_invoice: bool | NotGiven = NOT_GIVEN, ending_before: Union[str, datetime] | NotGiven = NOT_GIVEN, # 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. @@ -816,6 +839,11 @@ def update_end_date( 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. @@ -833,6 +861,7 @@ def update_end_date( { "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, @@ -860,7 +889,7 @@ def named_schedules(self) -> AsyncNamedSchedulesResource: @cached_property def with_raw_response(self) -> AsyncContractsResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -898,6 +927,7 @@ async def create( reseller_royalties: Iterable[contract_create_params.ResellerRoyalty] | NotGiven = NOT_GIVEN, salesforce_opportunity_id: str | NotGiven = NOT_GIVEN, scheduled_charges: Iterable[contract_create_params.ScheduledCharge] | NotGiven = NOT_GIVEN, + scheduled_charges_on_usage_invoices: Literal["ALL"] | NotGiven = NOT_GIVEN, total_contract_value: float | NotGiven = NOT_GIVEN, transition: contract_create_params.Transition | NotGiven = NOT_GIVEN, uniqueness_key: str | NotGiven = NOT_GIVEN, @@ -916,7 +946,7 @@ async def create( Args: starting_at: inclusive contract start time - billing_provider_configuration: This field's availability is dependent on your client's configuration. + billing_provider_configuration: The billing provider configuration associated with a contract. discounts: This field's availability is dependent on your client's configuration. @@ -938,6 +968,12 @@ async def create( 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. + 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 @@ -975,6 +1011,7 @@ async def create( "reseller_royalties": reseller_royalties, "salesforce_opportunity_id": salesforce_opportunity_id, "scheduled_charges": scheduled_charges, + "scheduled_charges_on_usage_invoices": scheduled_charges_on_usage_invoices, "total_contract_value": total_contract_value, "transition": transition, "uniqueness_key": uniqueness_key, @@ -994,6 +1031,7 @@ async def retrieve( *, contract_id: str, customer_id: str, + include_balance: bool | NotGiven = NOT_GIVEN, include_ledgers: bool | NotGiven = NOT_GIVEN, # 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. @@ -1006,6 +1044,9 @@ async def retrieve( Get a specific contract 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. @@ -1023,6 +1064,7 @@ async def retrieve( { "contract_id": contract_id, "customer_id": customer_id, + "include_balance": include_balance, "include_ledgers": include_ledgers, }, contract_retrieve_params.ContractRetrieveParams, @@ -1039,6 +1081,7 @@ async def list( customer_id: str, covering_date: Union[str, datetime] | NotGiven = NOT_GIVEN, include_archived: bool | NotGiven = NOT_GIVEN, + include_balance: bool | NotGiven = NOT_GIVEN, include_ledgers: bool | NotGiven = NOT_GIVEN, starting_at: Union[str, datetime] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -1058,6 +1101,9 @@ async def list( 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. @@ -1080,6 +1126,7 @@ async def list( "customer_id": customer_id, "covering_date": covering_date, "include_archived": include_archived, + "include_balance": include_balance, "include_ledgers": include_ledgers, "starting_at": starting_at, }, @@ -1332,6 +1379,7 @@ async def list_balances( covering_date: Union[str, datetime] | NotGiven = NOT_GIVEN, effective_before: Union[str, datetime] | NotGiven = NOT_GIVEN, include_archived: bool | NotGiven = NOT_GIVEN, + include_balance: bool | NotGiven = NOT_GIVEN, include_contract_balances: bool | NotGiven = NOT_GIVEN, include_ledgers: bool | NotGiven = NOT_GIVEN, next_page: str | NotGiven = NOT_GIVEN, @@ -1353,6 +1401,9 @@ async def list_balances( include_archived: Include 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 @@ -1379,6 +1430,7 @@ async def list_balances( "covering_date": covering_date, "effective_before": effective_before, "include_archived": include_archived, + "include_balance": include_balance, "include_contract_balances": include_contract_balances, "include_ledgers": include_ledgers, "next_page": next_page, @@ -1478,7 +1530,7 @@ async def schedule_pro_services_invoice( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> ContractScheduleProServicesInvoiceResponse: """ - Create a new, scheduled invoice for Professional Services terms on a contract. + Create a new scheduled invoice for Professional Services terms on a contract. This endpoint's availability is dependent on your client's configuration. Args: @@ -1568,6 +1620,7 @@ async def update_end_date( *, contract_id: str, customer_id: str, + allow_ending_before_finalized_invoice: bool | NotGiven = NOT_GIVEN, ending_before: Union[str, datetime] | NotGiven = NOT_GIVEN, # 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. @@ -1584,6 +1637,11 @@ async def update_end_date( 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. @@ -1601,6 +1659,7 @@ async def update_end_date( { "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, diff --git a/src/metronome/resources/contracts/named_schedules.py b/src/metronome/resources/contracts/named_schedules.py index 9555d9b4..2d0a2a54 100644 --- a/src/metronome/resources/contracts/named_schedules.py +++ b/src/metronome/resources/contracts/named_schedules.py @@ -31,7 +31,7 @@ class NamedSchedulesResource(SyncAPIResource): @cached_property def with_raw_response(self) -> NamedSchedulesResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -157,7 +157,7 @@ class AsyncNamedSchedulesResource(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncNamedSchedulesResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 diff --git a/src/metronome/resources/contracts/products.py b/src/metronome/resources/contracts/products.py index 5563d7a9..39ebe6b7 100644 --- a/src/metronome/resources/contracts/products.py +++ b/src/metronome/resources/contracts/products.py @@ -45,7 +45,7 @@ class ProductsResource(SyncAPIResource): @cached_property def with_raw_response(self) -> ProductsResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -101,16 +101,20 @@ def create( 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 + 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. + 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. + 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 @@ -250,10 +254,14 @@ def update( 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. + 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. + 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 @@ -397,7 +405,7 @@ class AsyncProductsResource(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncProductsResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -453,16 +461,20 @@ async def create( 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 + 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. + 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. + 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 @@ -602,10 +614,14 @@ async def update( 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. + 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. + 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 diff --git a/src/metronome/resources/contracts/rate_cards/named_schedules.py b/src/metronome/resources/contracts/rate_cards/named_schedules.py index a1507e02..5d241ad2 100644 --- a/src/metronome/resources/contracts/rate_cards/named_schedules.py +++ b/src/metronome/resources/contracts/rate_cards/named_schedules.py @@ -31,7 +31,7 @@ class NamedSchedulesResource(SyncAPIResource): @cached_property def with_raw_response(self) -> NamedSchedulesResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -165,7 +165,7 @@ class AsyncNamedSchedulesResource(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncNamedSchedulesResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 diff --git a/src/metronome/resources/contracts/rate_cards/product_orders.py b/src/metronome/resources/contracts/rate_cards/product_orders.py index d2f531e8..34ca2a8b 100644 --- a/src/metronome/resources/contracts/rate_cards/product_orders.py +++ b/src/metronome/resources/contracts/rate_cards/product_orders.py @@ -31,7 +31,7 @@ class ProductOrdersResource(SyncAPIResource): @cached_property def with_raw_response(self) -> ProductOrdersResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -134,7 +134,7 @@ class AsyncProductOrdersResource(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncProductOrdersResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 diff --git a/src/metronome/resources/contracts/rate_cards/rate_cards.py b/src/metronome/resources/contracts/rate_cards/rate_cards.py index 8ee17047..3f806e6a 100644 --- a/src/metronome/resources/contracts/rate_cards/rate_cards.py +++ b/src/metronome/resources/contracts/rate_cards/rate_cards.py @@ -78,7 +78,7 @@ def named_schedules(self) -> NamedSchedulesResource: @cached_property def with_raw_response(self) -> RateCardsResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -123,8 +123,8 @@ def create( credit_type_conversions: Required when using custom pricing units in rates. - fiat_credit_type_id: "The Metronome ID of the credit type to associate with the rate card, defaults - to USD (cents) if not passed." + 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 @@ -191,7 +191,6 @@ def update( *, rate_card_id: str, aliases: Iterable[rate_card_update_params.Alias] | NotGiven = NOT_GIVEN, - custom_fields: Dict[str, str] | NotGiven = NOT_GIVEN, description: str | NotGiven = NOT_GIVEN, name: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -227,7 +226,6 @@ def update( { "rate_card_id": rate_card_id, "aliases": aliases, - "custom_fields": custom_fields, "description": description, "name": name, }, @@ -307,7 +305,8 @@ def retrieve_rate_schedule( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> RateCardRetrieveRateScheduleResponse: """ - Get a specific rate schedule including all rate card entries + Get all rates for a rate card from starting_at (either in perpetuity or until + ending_before, if provided) Args: rate_card_id: ID of the rate card to get the schedule for @@ -376,7 +375,7 @@ def named_schedules(self) -> AsyncNamedSchedulesResource: @cached_property def with_raw_response(self) -> AsyncRateCardsResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -421,8 +420,8 @@ async def create( credit_type_conversions: Required when using custom pricing units in rates. - fiat_credit_type_id: "The Metronome ID of the credit type to associate with the rate card, defaults - to USD (cents) if not passed." + 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 @@ -489,7 +488,6 @@ async def update( *, rate_card_id: str, aliases: Iterable[rate_card_update_params.Alias] | NotGiven = NOT_GIVEN, - custom_fields: Dict[str, str] | NotGiven = NOT_GIVEN, description: str | NotGiven = NOT_GIVEN, name: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -525,7 +523,6 @@ async def update( { "rate_card_id": rate_card_id, "aliases": aliases, - "custom_fields": custom_fields, "description": description, "name": name, }, @@ -605,7 +602,8 @@ async def retrieve_rate_schedule( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> RateCardRetrieveRateScheduleResponse: """ - Get a specific rate schedule including all rate card entries + Get all rates for a rate card from starting_at (either in perpetuity or until + ending_before, if provided) Args: rate_card_id: ID of the rate card to get the schedule for diff --git a/src/metronome/resources/contracts/rate_cards/rates.py b/src/metronome/resources/contracts/rate_cards/rates.py index 35cbda8c..fa6701fb 100644 --- a/src/metronome/resources/contracts/rate_cards/rates.py +++ b/src/metronome/resources/contracts/rate_cards/rates.py @@ -36,7 +36,7 @@ class RatesResource(SyncAPIResource): @cached_property def with_raw_response(self) -> RatesResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -68,7 +68,7 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> SyncCursorPage[RateListResponse]: """ - Get rate card rates for a specific time. + Get all rates for a rate card at a point in time Args: at: inclusive starting point for the rates schedule @@ -126,6 +126,7 @@ def add( rate_card_id: str, rate_type: Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "TIERED", "CUSTOM"], starting_at: Union[str, datetime], + commit_rate: rate_add_params.CommitRate | NotGiven = NOT_GIVEN, credit_type_id: str | NotGiven = NOT_GIVEN, custom_rate: Dict[str, object] | NotGiven = NOT_GIVEN, ending_before: Union[str, datetime] | NotGiven = NOT_GIVEN, @@ -152,16 +153,20 @@ def add( starting_at: inclusive effective date - credit_type_id: "The Metronome ID of the credit type to associate with price, defaults to USD + 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." + 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. + 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 @@ -195,6 +200,7 @@ def add( "rate_card_id": rate_card_id, "rate_type": rate_type, "starting_at": starting_at, + "commit_rate": commit_rate, "credit_type_id": credit_type_id, "custom_rate": custom_rate, "ending_before": ending_before, @@ -216,8 +222,8 @@ def add( def add_many( self, *, - rate_card_id: str | NotGiven = NOT_GIVEN, - rates: Iterable[rate_add_many_params.Rate] | NotGiven = NOT_GIVEN, + 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, @@ -257,7 +263,7 @@ class AsyncRatesResource(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncRatesResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -289,7 +295,7 @@ def list( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> AsyncPaginator[RateListResponse, AsyncCursorPage[RateListResponse]]: """ - Get rate card rates for a specific time. + Get all rates for a rate card at a point in time Args: at: inclusive starting point for the rates schedule @@ -347,6 +353,7 @@ async def add( rate_card_id: str, rate_type: Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "TIERED", "CUSTOM"], starting_at: Union[str, datetime], + commit_rate: rate_add_params.CommitRate | NotGiven = NOT_GIVEN, credit_type_id: str | NotGiven = NOT_GIVEN, custom_rate: Dict[str, object] | NotGiven = NOT_GIVEN, ending_before: Union[str, datetime] | NotGiven = NOT_GIVEN, @@ -373,16 +380,20 @@ async def add( starting_at: inclusive effective date - credit_type_id: "The Metronome ID of the credit type to associate with price, defaults to USD + 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." + 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. + 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 @@ -416,6 +427,7 @@ async def add( "rate_card_id": rate_card_id, "rate_type": rate_type, "starting_at": starting_at, + "commit_rate": commit_rate, "credit_type_id": credit_type_id, "custom_rate": custom_rate, "ending_before": ending_before, @@ -437,8 +449,8 @@ async def add( async def add_many( self, *, - rate_card_id: str | NotGiven = NOT_GIVEN, - rates: Iterable[rate_add_many_params.Rate] | NotGiven = NOT_GIVEN, + 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, diff --git a/src/metronome/resources/credit_grants.py b/src/metronome/resources/credit_grants.py index 2af4f627..83d1e0ce 100644 --- a/src/metronome/resources/credit_grants.py +++ b/src/metronome/resources/credit_grants.py @@ -44,7 +44,7 @@ class CreditGrantsResource(SyncAPIResource): @cached_property def with_raw_response(self) -> CreditGrantsResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -90,8 +90,7 @@ def create( Args: customer_id: the Metronome ID of the customer - expires_at: The credit grant will only apply to billing periods that end before this - timestamp. + expires_at: The credit grant will only apply to usage or charges dated before this timestamp grant_amount: the amount of credits granted @@ -101,8 +100,8 @@ def create( custom_fields: Custom fields to attach to the credit grant. - effective_at: The credit grant will only apply to billing periods that end at or after this - timestamp. + 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. @@ -448,7 +447,7 @@ class AsyncCreditGrantsResource(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncCreditGrantsResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -494,8 +493,7 @@ async def create( Args: customer_id: the Metronome ID of the customer - expires_at: The credit grant will only apply to billing periods that end before this - timestamp. + expires_at: The credit grant will only apply to usage or charges dated before this timestamp grant_amount: the amount of credits granted @@ -505,8 +503,8 @@ async def create( custom_fields: Custom fields to attach to the credit grant. - effective_at: The credit grant will only apply to billing periods that end at or after this - timestamp. + 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. diff --git a/src/metronome/resources/custom_fields.py b/src/metronome/resources/custom_fields.py index 539390fb..47c2ce6d 100644 --- a/src/metronome/resources/custom_fields.py +++ b/src/metronome/resources/custom_fields.py @@ -37,7 +37,7 @@ class CustomFieldsResource(SyncAPIResource): @cached_property def with_raw_response(self) -> CustomFieldsResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -68,6 +68,7 @@ def add_key( "credit_grant", "customer_plan", "customer", + "discount", "invoice", "plan", "professional_service", @@ -128,6 +129,7 @@ def delete_values( "credit_grant", "customer_plan", "customer", + "discount", "invoice", "plan", "professional_service", @@ -189,6 +191,7 @@ def list_keys( "credit_grant", "customer_plan", "customer", + "discount", "invoice", "plan", "professional_service", @@ -250,6 +253,7 @@ def remove_key( "credit_grant", "customer_plan", "customer", + "discount", "invoice", "plan", "professional_service", @@ -308,6 +312,7 @@ def set_values( "credit_grant", "customer_plan", "customer", + "discount", "invoice", "plan", "professional_service", @@ -364,7 +369,7 @@ class AsyncCustomFieldsResource(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncCustomFieldsResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -395,6 +400,7 @@ async def add_key( "credit_grant", "customer_plan", "customer", + "discount", "invoice", "plan", "professional_service", @@ -455,6 +461,7 @@ async def delete_values( "credit_grant", "customer_plan", "customer", + "discount", "invoice", "plan", "professional_service", @@ -516,6 +523,7 @@ async def list_keys( "credit_grant", "customer_plan", "customer", + "discount", "invoice", "plan", "professional_service", @@ -579,6 +587,7 @@ async def remove_key( "credit_grant", "customer_plan", "customer", + "discount", "invoice", "plan", "professional_service", @@ -637,6 +646,7 @@ async def set_values( "credit_grant", "customer_plan", "customer", + "discount", "invoice", "plan", "professional_service", diff --git a/src/metronome/resources/customers/alerts.py b/src/metronome/resources/customers/alerts.py index 7cfd0abb..bce901b8 100644 --- a/src/metronome/resources/customers/alerts.py +++ b/src/metronome/resources/customers/alerts.py @@ -32,7 +32,7 @@ class AlertsResource(SyncAPIResource): @cached_property def with_raw_response(self) -> AlertsResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -192,7 +192,7 @@ class AsyncAlertsResource(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncAlertsResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 diff --git a/src/metronome/resources/customers/billing_config.py b/src/metronome/resources/customers/billing_config.py index d1083b1d..436c5c2f 100644 --- a/src/metronome/resources/customers/billing_config.py +++ b/src/metronome/resources/customers/billing_config.py @@ -30,7 +30,7 @@ class BillingConfigResource(SyncAPIResource): @cached_property def with_raw_response(self) -> BillingConfigResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -48,6 +48,8 @@ def with_streaming_response(self) -> BillingConfigResourceWithStreamingResponse: def create( self, + *, + customer_id: str, billing_provider_type: Literal[ "aws_marketplace", "stripe", @@ -58,8 +60,6 @@ def create( "workday", "gcp_marketplace", ], - *, - customer_id: str, billing_provider_customer_id: str, aws_product_code: str | NotGiven = NOT_GIVEN, aws_region: Literal[ @@ -139,6 +139,8 @@ def create( def retrieve( self, + *, + customer_id: str, billing_provider_type: Literal[ "aws_marketplace", "stripe", @@ -149,8 +151,6 @@ def retrieve( "workday", "gcp_marketplace", ], - *, - 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, @@ -186,6 +186,8 @@ def retrieve( def delete( self, + *, + customer_id: str, billing_provider_type: Literal[ "aws_marketplace", "stripe", @@ -196,8 +198,6 @@ def delete( "workday", "gcp_marketplace", ], - *, - 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, @@ -239,7 +239,7 @@ class AsyncBillingConfigResource(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncBillingConfigResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -257,6 +257,8 @@ def with_streaming_response(self) -> AsyncBillingConfigResourceWithStreamingResp async def create( self, + *, + customer_id: str, billing_provider_type: Literal[ "aws_marketplace", "stripe", @@ -267,8 +269,6 @@ async def create( "workday", "gcp_marketplace", ], - *, - customer_id: str, billing_provider_customer_id: str, aws_product_code: str | NotGiven = NOT_GIVEN, aws_region: Literal[ @@ -348,6 +348,8 @@ async def create( async def retrieve( self, + *, + customer_id: str, billing_provider_type: Literal[ "aws_marketplace", "stripe", @@ -358,8 +360,6 @@ async def retrieve( "workday", "gcp_marketplace", ], - *, - 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, @@ -395,6 +395,8 @@ async def retrieve( async def delete( self, + *, + customer_id: str, billing_provider_type: Literal[ "aws_marketplace", "stripe", @@ -405,8 +407,6 @@ async def delete( "workday", "gcp_marketplace", ], - *, - 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, diff --git a/src/metronome/resources/customers/commits.py b/src/metronome/resources/customers/commits.py index c85ee77c..5c730839 100644 --- a/src/metronome/resources/customers/commits.py +++ b/src/metronome/resources/customers/commits.py @@ -34,7 +34,7 @@ class CommitsResource(SyncAPIResource): @cached_property def with_raw_response(self) -> CommitsResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -67,7 +67,9 @@ def create( invoice_schedule: commit_create_params.InvoiceSchedule | NotGiven = NOT_GIVEN, name: str | NotGiven = NOT_GIVEN, netsuite_sales_order_id: str | NotGiven = NOT_GIVEN, + rate_type: Literal["COMMIT_RATE", "commit_rate", "LIST_RATE", "list_rate"] | NotGiven = NOT_GIVEN, salesforce_opportunity_id: str | NotGiven = NOT_GIVEN, + uniqueness_key: str | NotGiven = NOT_GIVEN, # 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, @@ -85,6 +87,9 @@ def create( 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. @@ -111,6 +116,11 @@ def create( salesforce_opportunity_id: This field's availability is dependent on your client's configuration. + 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 @@ -137,7 +147,9 @@ def create( "invoice_schedule": invoice_schedule, "name": name, "netsuite_sales_order_id": netsuite_sales_order_id, + "rate_type": rate_type, "salesforce_opportunity_id": salesforce_opportunity_id, + "uniqueness_key": uniqueness_key, }, commit_create_params.CommitCreateParams, ), @@ -155,6 +167,7 @@ def list( covering_date: Union[str, datetime] | NotGiven = NOT_GIVEN, effective_before: Union[str, datetime] | NotGiven = NOT_GIVEN, include_archived: bool | NotGiven = NOT_GIVEN, + include_balance: bool | NotGiven = NOT_GIVEN, include_contract_commits: bool | NotGiven = NOT_GIVEN, include_ledgers: bool | NotGiven = NOT_GIVEN, next_page: str | NotGiven = NOT_GIVEN, @@ -176,6 +189,9 @@ def list( include_archived: Include 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 @@ -202,6 +218,7 @@ def list( "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, "next_page": next_page, @@ -274,7 +291,7 @@ class AsyncCommitsResource(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncCommitsResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -307,7 +324,9 @@ async def create( invoice_schedule: commit_create_params.InvoiceSchedule | NotGiven = NOT_GIVEN, name: str | NotGiven = NOT_GIVEN, netsuite_sales_order_id: str | NotGiven = NOT_GIVEN, + rate_type: Literal["COMMIT_RATE", "commit_rate", "LIST_RATE", "list_rate"] | NotGiven = NOT_GIVEN, salesforce_opportunity_id: str | NotGiven = NOT_GIVEN, + uniqueness_key: str | NotGiven = NOT_GIVEN, # 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, @@ -325,6 +344,9 @@ async def create( 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. @@ -351,6 +373,11 @@ async def create( salesforce_opportunity_id: This field's availability is dependent on your client's configuration. + 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 @@ -377,7 +404,9 @@ async def create( "invoice_schedule": invoice_schedule, "name": name, "netsuite_sales_order_id": netsuite_sales_order_id, + "rate_type": rate_type, "salesforce_opportunity_id": salesforce_opportunity_id, + "uniqueness_key": uniqueness_key, }, commit_create_params.CommitCreateParams, ), @@ -395,6 +424,7 @@ async def list( covering_date: Union[str, datetime] | NotGiven = NOT_GIVEN, effective_before: Union[str, datetime] | NotGiven = NOT_GIVEN, include_archived: bool | NotGiven = NOT_GIVEN, + include_balance: bool | NotGiven = NOT_GIVEN, include_contract_commits: bool | NotGiven = NOT_GIVEN, include_ledgers: bool | NotGiven = NOT_GIVEN, next_page: str | NotGiven = NOT_GIVEN, @@ -416,6 +446,9 @@ async def list( include_archived: Include 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 @@ -442,6 +475,7 @@ async def list( "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, "next_page": next_page, diff --git a/src/metronome/resources/customers/credits.py b/src/metronome/resources/customers/credits.py index 1f74855f..9a5735a6 100644 --- a/src/metronome/resources/customers/credits.py +++ b/src/metronome/resources/customers/credits.py @@ -4,6 +4,7 @@ from typing import Dict, List, Union from datetime import datetime +from typing_extensions import Literal import httpx @@ -33,7 +34,7 @@ class CreditsResource(SyncAPIResource): @cached_property def with_raw_response(self) -> CreditsResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -63,7 +64,9 @@ def create( description: str | NotGiven = NOT_GIVEN, name: str | NotGiven = NOT_GIVEN, netsuite_sales_order_id: str | NotGiven = NOT_GIVEN, + rate_type: Literal["COMMIT_RATE", "commit_rate", "LIST_RATE", "list_rate"] | NotGiven = NOT_GIVEN, salesforce_opportunity_id: str | NotGiven = NOT_GIVEN, + uniqueness_key: str | NotGiven = NOT_GIVEN, # 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, @@ -97,6 +100,11 @@ def create( salesforce_opportunity_id: This field's availability is dependent on your client's configuration. + 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 @@ -120,7 +128,9 @@ def create( "description": description, "name": name, "netsuite_sales_order_id": netsuite_sales_order_id, + "rate_type": rate_type, "salesforce_opportunity_id": salesforce_opportunity_id, + "uniqueness_key": uniqueness_key, }, credit_create_params.CreditCreateParams, ), @@ -138,6 +148,7 @@ def list( credit_id: str | NotGiven = NOT_GIVEN, effective_before: Union[str, datetime] | NotGiven = NOT_GIVEN, include_archived: bool | NotGiven = NOT_GIVEN, + include_balance: bool | NotGiven = NOT_GIVEN, include_contract_credits: bool | NotGiven = NOT_GIVEN, include_ledgers: bool | NotGiven = NOT_GIVEN, next_page: str | NotGiven = NOT_GIVEN, @@ -159,6 +170,9 @@ def list( include_archived: Include 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 @@ -185,6 +199,7 @@ def list( "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, "next_page": next_page, @@ -251,7 +266,7 @@ class AsyncCreditsResource(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncCreditsResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -281,7 +296,9 @@ async def create( description: str | NotGiven = NOT_GIVEN, name: str | NotGiven = NOT_GIVEN, netsuite_sales_order_id: str | NotGiven = NOT_GIVEN, + rate_type: Literal["COMMIT_RATE", "commit_rate", "LIST_RATE", "list_rate"] | NotGiven = NOT_GIVEN, salesforce_opportunity_id: str | NotGiven = NOT_GIVEN, + uniqueness_key: str | NotGiven = NOT_GIVEN, # 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, @@ -315,6 +332,11 @@ async def create( salesforce_opportunity_id: This field's availability is dependent on your client's configuration. + 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 @@ -338,7 +360,9 @@ async def create( "description": description, "name": name, "netsuite_sales_order_id": netsuite_sales_order_id, + "rate_type": rate_type, "salesforce_opportunity_id": salesforce_opportunity_id, + "uniqueness_key": uniqueness_key, }, credit_create_params.CreditCreateParams, ), @@ -356,6 +380,7 @@ async def list( credit_id: str | NotGiven = NOT_GIVEN, effective_before: Union[str, datetime] | NotGiven = NOT_GIVEN, include_archived: bool | NotGiven = NOT_GIVEN, + include_balance: bool | NotGiven = NOT_GIVEN, include_contract_credits: bool | NotGiven = NOT_GIVEN, include_ledgers: bool | NotGiven = NOT_GIVEN, next_page: str | NotGiven = NOT_GIVEN, @@ -377,6 +402,9 @@ async def list( include_archived: Include 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 @@ -403,6 +431,7 @@ async def list( "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, "next_page": next_page, diff --git a/src/metronome/resources/customers/customers.py b/src/metronome/resources/customers/customers.py index 0aa1cb4e..db43626a 100644 --- a/src/metronome/resources/customers/customers.py +++ b/src/metronome/resources/customers/customers.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict, List, Union, Optional +from typing import Dict, List, Union, Iterable, Optional from datetime import datetime import httpx @@ -131,7 +131,7 @@ def named_schedules(self) -> NamedSchedulesResource: @cached_property def with_raw_response(self) -> CustomersResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -153,6 +153,8 @@ def create( name: str, billing_config: customer_create_params.BillingConfig | NotGiven = NOT_GIVEN, custom_fields: Dict[str, str] | NotGiven = NOT_GIVEN, + customer_billing_provider_configurations: Iterable[customer_create_params.CustomerBillingProviderConfiguration] + | NotGiven = NOT_GIVEN, external_id: str | NotGiven = NOT_GIVEN, ingest_aliases: List[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -168,8 +170,8 @@ def create( Args: name: This will be truncated to 160 characters if the provided name is longer. - external_id: (deprecated, use ingest_aliases instead) the first ID (Metronome ID or ingest - alias) that can be used in usage events + 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 @@ -188,6 +190,7 @@ def create( "name": name, "billing_config": billing_config, "custom_fields": custom_fields, + "customer_billing_provider_configurations": customer_billing_provider_configurations, "external_id": external_id, "ingest_aliases": ingest_aliases, }, @@ -201,8 +204,8 @@ def create( def retrieve( self, - customer_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, @@ -330,8 +333,9 @@ def archive( def list_billable_metrics( self, - customer_id: str, *, + customer_id: str, + include_archived: bool | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, next_page: str | NotGiven = NOT_GIVEN, on_current_plan: bool | NotGiven = NOT_GIVEN, @@ -346,6 +350,8 @@ def list_billable_metrics( Get all billable metrics 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. @@ -373,6 +379,7 @@ def list_billable_metrics( timeout=timeout, query=maybe_transform( { + "include_archived": include_archived, "limit": limit, "next_page": next_page, "on_current_plan": on_current_plan, @@ -385,8 +392,8 @@ def list_billable_metrics( def list_costs( self, - customer_id: str, *, + customer_id: str, ending_before: Union[str, datetime], starting_on: Union[str, datetime], limit: int | NotGiven = NOT_GIVEN, @@ -445,8 +452,8 @@ def list_costs( def set_ingest_aliases( self, - customer_id: str, *, + customer_id: str, ingest_aliases: List[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. @@ -486,8 +493,8 @@ def set_ingest_aliases( def set_name( self, - customer_id: str, *, + 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. @@ -524,8 +531,8 @@ def set_name( def update_config( self, - customer_id: str, *, + customer_id: str, leave_stripe_invoices_in_draft: Optional[bool] | NotGiven = NOT_GIVEN, salesforce_account_id: Optional[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -603,7 +610,7 @@ def named_schedules(self) -> AsyncNamedSchedulesResource: @cached_property def with_raw_response(self) -> AsyncCustomersResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -625,6 +632,8 @@ async def create( name: str, billing_config: customer_create_params.BillingConfig | NotGiven = NOT_GIVEN, custom_fields: Dict[str, str] | NotGiven = NOT_GIVEN, + customer_billing_provider_configurations: Iterable[customer_create_params.CustomerBillingProviderConfiguration] + | NotGiven = NOT_GIVEN, external_id: str | NotGiven = NOT_GIVEN, ingest_aliases: List[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -640,8 +649,8 @@ async def create( Args: name: This will be truncated to 160 characters if the provided name is longer. - external_id: (deprecated, use ingest_aliases instead) the first ID (Metronome ID or ingest - alias) that can be used in usage events + 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 @@ -660,6 +669,7 @@ async def create( "name": name, "billing_config": billing_config, "custom_fields": custom_fields, + "customer_billing_provider_configurations": customer_billing_provider_configurations, "external_id": external_id, "ingest_aliases": ingest_aliases, }, @@ -673,8 +683,8 @@ async def create( async def retrieve( self, - customer_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, @@ -802,8 +812,9 @@ async def archive( def list_billable_metrics( self, - customer_id: str, *, + customer_id: str, + include_archived: bool | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, next_page: str | NotGiven = NOT_GIVEN, on_current_plan: bool | NotGiven = NOT_GIVEN, @@ -818,6 +829,8 @@ def list_billable_metrics( Get all billable metrics 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. @@ -845,6 +858,7 @@ def list_billable_metrics( timeout=timeout, query=maybe_transform( { + "include_archived": include_archived, "limit": limit, "next_page": next_page, "on_current_plan": on_current_plan, @@ -857,8 +871,8 @@ def list_billable_metrics( def list_costs( self, - customer_id: str, *, + customer_id: str, ending_before: Union[str, datetime], starting_on: Union[str, datetime], limit: int | NotGiven = NOT_GIVEN, @@ -917,8 +931,8 @@ def list_costs( async def set_ingest_aliases( self, - customer_id: str, *, + customer_id: str, ingest_aliases: List[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. @@ -958,8 +972,8 @@ async def set_ingest_aliases( async def set_name( self, - customer_id: str, *, + 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. @@ -996,8 +1010,8 @@ async def set_name( async def update_config( self, - customer_id: str, *, + customer_id: str, leave_stripe_invoices_in_draft: Optional[bool] | NotGiven = NOT_GIVEN, salesforce_account_id: Optional[str] | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. diff --git a/src/metronome/resources/customers/invoices.py b/src/metronome/resources/customers/invoices.py index 078dc042..2202d33d 100644 --- a/src/metronome/resources/customers/invoices.py +++ b/src/metronome/resources/customers/invoices.py @@ -41,7 +41,7 @@ class InvoicesResource(SyncAPIResource): @cached_property def with_raw_response(self) -> InvoicesResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -59,9 +59,9 @@ def with_streaming_response(self) -> InvoicesResourceWithStreamingResponse: def retrieve( self, - invoice_id: str, *, customer_id: str, + invoice_id: str, skip_zero_qty_line_items: bool | NotGiven = NOT_GIVEN, # 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. @@ -105,8 +105,8 @@ def retrieve( def list( self, - customer_id: str, *, + customer_id: str, credit_type_id: str | NotGiven = NOT_GIVEN, ending_before: Union[str, datetime] | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, @@ -183,8 +183,8 @@ def list( def add_charge( self, - customer_id: str, *, + customer_id: str, charge_id: str, customer_plan_id: str, description: str, @@ -244,8 +244,8 @@ def add_charge( def list_breakdowns( self, - customer_id: str, *, + customer_id: str, ending_before: Union[str, datetime], starting_on: Union[str, datetime], credit_type_id: str | NotGiven = NOT_GIVEN, @@ -263,7 +263,7 @@ def list_breakdowns( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> SyncCursorPage[InvoiceListBreakdownsResponse]: """ - List daily or hourly breakdown invoices for a given customer, optionally + List daily or hourly invoice breakdowns for a given customer, optionally filtered by status, date range, and/or credit type. Args: @@ -332,7 +332,7 @@ class AsyncInvoicesResource(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncInvoicesResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -350,9 +350,9 @@ def with_streaming_response(self) -> AsyncInvoicesResourceWithStreamingResponse: async def retrieve( self, - invoice_id: str, *, customer_id: str, + invoice_id: str, skip_zero_qty_line_items: bool | NotGiven = NOT_GIVEN, # 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. @@ -396,8 +396,8 @@ async def retrieve( def list( self, - customer_id: str, *, + customer_id: str, credit_type_id: str | NotGiven = NOT_GIVEN, ending_before: Union[str, datetime] | NotGiven = NOT_GIVEN, limit: int | NotGiven = NOT_GIVEN, @@ -474,8 +474,8 @@ def list( async def add_charge( self, - customer_id: str, *, + customer_id: str, charge_id: str, customer_plan_id: str, description: str, @@ -535,8 +535,8 @@ async def add_charge( def list_breakdowns( self, - customer_id: str, *, + customer_id: str, ending_before: Union[str, datetime], starting_on: Union[str, datetime], credit_type_id: str | NotGiven = NOT_GIVEN, @@ -554,7 +554,7 @@ def list_breakdowns( timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN, ) -> AsyncPaginator[InvoiceListBreakdownsResponse, AsyncCursorPage[InvoiceListBreakdownsResponse]]: """ - List daily or hourly breakdown invoices for a given customer, optionally + List daily or hourly invoice breakdowns for a given customer, optionally filtered by status, date range, and/or credit type. Args: diff --git a/src/metronome/resources/customers/named_schedules.py b/src/metronome/resources/customers/named_schedules.py index e6a48261..e2c32062 100644 --- a/src/metronome/resources/customers/named_schedules.py +++ b/src/metronome/resources/customers/named_schedules.py @@ -31,7 +31,7 @@ class NamedSchedulesResource(SyncAPIResource): @cached_property def with_raw_response(self) -> NamedSchedulesResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -157,7 +157,7 @@ class AsyncNamedSchedulesResource(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncNamedSchedulesResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 diff --git a/src/metronome/resources/customers/plans.py b/src/metronome/resources/customers/plans.py index 78e3d567..e13d3b4b 100644 --- a/src/metronome/resources/customers/plans.py +++ b/src/metronome/resources/customers/plans.py @@ -35,7 +35,7 @@ class PlansResource(SyncAPIResource): @cached_property def with_raw_response(self) -> PlansResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -53,8 +53,8 @@ def with_streaming_response(self) -> PlansResourceWithStreamingResponse: def list( self, - customer_id: str, *, + customer_id: str, limit: int | NotGiven = NOT_GIVEN, next_page: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -103,8 +103,8 @@ def list( def add( self, - customer_id: str, *, + customer_id: str, plan_id: str, starting_on: Union[str, datetime], ending_before: Union[str, datetime] | NotGiven = NOT_GIVEN, @@ -122,7 +122,7 @@ def add( """Associate an existing customer with a plan for a specified date range. See the - [price adjustments documentation](https://docs.metronome.com/pricing/managing-plans/#price-adjustments) + [price adjustments documentation](https://plans-docs.metronome.com/pricing/managing-plans/#price-adjustments) for details on the price adjustments. Args: @@ -140,7 +140,7 @@ def add( price_adjustments: A list of price adjustments can be applied on top of the pricing in the plans. See the - [price adjustments documentation](https://docs.metronome.com/pricing/managing-plans/#price-adjustments) + [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 @@ -179,9 +179,9 @@ def add( def end( self, - customer_plan_id: str, *, customer_id: str, + customer_plan_id: str, ending_before: Union[str, datetime] | NotGiven = NOT_GIVEN, void_invoices: bool | NotGiven = NOT_GIVEN, void_stripe_invoices: bool | NotGiven = NOT_GIVEN, @@ -236,9 +236,9 @@ def end( def list_price_adjustments( self, - customer_plan_id: str, *, customer_id: str, + customer_plan_id: str, limit: int | NotGiven = NOT_GIVEN, next_page: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -251,7 +251,7 @@ def list_price_adjustments( """Lists a customer plans adjustments. See the - [price adjustments documentation](https://docs.metronome.com/pricing/managing-plans/#price-adjustments) + [price adjustments documentation](https://plans-docs.metronome.com/pricing/managing-plans/#price-adjustments) for details. Args: @@ -295,7 +295,7 @@ class AsyncPlansResource(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncPlansResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -313,8 +313,8 @@ def with_streaming_response(self) -> AsyncPlansResourceWithStreamingResponse: def list( self, - customer_id: str, *, + customer_id: str, limit: int | NotGiven = NOT_GIVEN, next_page: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -363,8 +363,8 @@ def list( async def add( self, - customer_id: str, *, + customer_id: str, plan_id: str, starting_on: Union[str, datetime], ending_before: Union[str, datetime] | NotGiven = NOT_GIVEN, @@ -382,7 +382,7 @@ async def add( """Associate an existing customer with a plan for a specified date range. See the - [price adjustments documentation](https://docs.metronome.com/pricing/managing-plans/#price-adjustments) + [price adjustments documentation](https://plans-docs.metronome.com/pricing/managing-plans/#price-adjustments) for details on the price adjustments. Args: @@ -400,7 +400,7 @@ async def add( price_adjustments: A list of price adjustments can be applied on top of the pricing in the plans. See the - [price adjustments documentation](https://docs.metronome.com/pricing/managing-plans/#price-adjustments) + [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 @@ -439,9 +439,9 @@ async def add( async def end( self, - customer_plan_id: str, *, customer_id: str, + customer_plan_id: str, ending_before: Union[str, datetime] | NotGiven = NOT_GIVEN, void_invoices: bool | NotGiven = NOT_GIVEN, void_stripe_invoices: bool | NotGiven = NOT_GIVEN, @@ -496,9 +496,9 @@ async def end( def list_price_adjustments( self, - customer_plan_id: str, *, customer_id: str, + customer_plan_id: str, limit: int | NotGiven = NOT_GIVEN, next_page: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -511,7 +511,7 @@ def list_price_adjustments( """Lists a customer plans adjustments. See the - [price adjustments documentation](https://docs.metronome.com/pricing/managing-plans/#price-adjustments) + [price adjustments documentation](https://plans-docs.metronome.com/pricing/managing-plans/#price-adjustments) for details. Args: diff --git a/src/metronome/resources/dashboards.py b/src/metronome/resources/dashboards.py index cf54bebd..02296f7a 100644 --- a/src/metronome/resources/dashboards.py +++ b/src/metronome/resources/dashboards.py @@ -31,7 +31,7 @@ class DashboardsResource(SyncAPIResource): @cached_property def with_raw_response(self) -> DashboardsResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -108,7 +108,7 @@ class AsyncDashboardsResource(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncDashboardsResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 diff --git a/src/metronome/resources/invoices.py b/src/metronome/resources/invoices.py index c53a1ae0..39c7e4cf 100644 --- a/src/metronome/resources/invoices.py +++ b/src/metronome/resources/invoices.py @@ -29,7 +29,7 @@ class InvoicesResource(SyncAPIResource): @cached_property def with_raw_response(self) -> InvoicesResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -118,7 +118,7 @@ class AsyncInvoicesResource(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncInvoicesResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 diff --git a/src/metronome/resources/plans.py b/src/metronome/resources/plans.py index 1e376891..9c73c766 100644 --- a/src/metronome/resources/plans.py +++ b/src/metronome/resources/plans.py @@ -31,7 +31,7 @@ class PlansResource(SyncAPIResource): @cached_property def with_raw_response(self) -> PlansResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -96,8 +96,8 @@ def list( def get_details( self, - plan_id: str, *, + 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, @@ -129,8 +129,8 @@ def get_details( def list_charges( self, - plan_id: str, *, + plan_id: str, limit: int | NotGiven = NOT_GIVEN, next_page: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -179,8 +179,8 @@ def list_charges( def list_customers( self, - plan_id: str, *, + plan_id: str, limit: int | NotGiven = NOT_GIVEN, next_page: str | NotGiven = NOT_GIVEN, status: Literal["all", "active", "ended", "upcoming"] | NotGiven = NOT_GIVEN, @@ -245,7 +245,7 @@ class AsyncPlansResource(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncPlansResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -310,8 +310,8 @@ def list( async def get_details( self, - plan_id: str, *, + 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, @@ -343,8 +343,8 @@ async def get_details( def list_charges( self, - plan_id: str, *, + plan_id: str, limit: int | NotGiven = NOT_GIVEN, next_page: str | NotGiven = NOT_GIVEN, # Use the following arguments if you need to pass additional parameters to the API that aren't available via kwargs. @@ -393,8 +393,8 @@ def list_charges( def list_customers( self, - plan_id: str, *, + plan_id: str, limit: int | NotGiven = NOT_GIVEN, next_page: str | NotGiven = NOT_GIVEN, status: Literal["all", "active", "ended", "upcoming"] | NotGiven = NOT_GIVEN, diff --git a/src/metronome/resources/services.py b/src/metronome/resources/services.py index 677bbfc3..e1ab1642 100644 --- a/src/metronome/resources/services.py +++ b/src/metronome/resources/services.py @@ -23,7 +23,7 @@ class ServicesResource(SyncAPIResource): @cached_property def with_raw_response(self) -> ServicesResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -69,7 +69,7 @@ class AsyncServicesResource(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncServicesResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 diff --git a/src/metronome/resources/usage.py b/src/metronome/resources/usage.py index e664ff53..d98c1b9f 100644 --- a/src/metronome/resources/usage.py +++ b/src/metronome/resources/usage.py @@ -34,7 +34,7 @@ class UsageResource(SyncAPIResource): @cached_property def with_raw_response(self) -> UsageResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -129,8 +129,8 @@ def ingest( The body of this request is expected to be a JSON array of between 1 and 100 usage events. Compressed request bodies are supported with a `Content-Encoding: gzip` header. See - [Getting usage into Metronome](https://docs.metronome.com/getting-usage-data-into-metronome/overview) - to learn more about usage events. + [Getting usage into Metronome](https://docs.metronome.com/connect-metronome/) to + learn more about usage events. Args: extra_headers: Send extra headers @@ -232,7 +232,7 @@ class AsyncUsageResource(AsyncAPIResource): @cached_property def with_raw_response(self) -> AsyncUsageResourceWithRawResponse: """ - This property can be used as a prefix for any HTTP method call to return the + 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 @@ -327,8 +327,8 @@ async def ingest( The body of this request is expected to be a JSON array of between 1 and 100 usage events. Compressed request bodies are supported with a `Content-Encoding: gzip` header. See - [Getting usage into Metronome](https://docs.metronome.com/getting-usage-data-into-metronome/overview) - to learn more about usage events. + [Getting usage into Metronome](https://docs.metronome.com/connect-metronome/) to + learn more about usage events. Args: extra_headers: Send extra headers diff --git a/src/metronome/types/__init__.py b/src/metronome/types/__init__.py index 4914028a..47d9e735 100644 --- a/src/metronome/types/__init__.py +++ b/src/metronome/types/__init__.py @@ -10,8 +10,8 @@ Credit as Credit, Discount as Discount, Override as Override, - CreditType as CreditType, ProService as ProService, + CreditTypeData as CreditTypeData, PropertyFilter as PropertyFilter, BaseUsageFilter as BaseUsageFilter, EventTypeFilter as EventTypeFilter, diff --git a/src/metronome/types/alert_archive_params.py b/src/metronome/types/alert_archive_params.py index abc96015..b538b4f5 100644 --- a/src/metronome/types/alert_archive_params.py +++ b/src/metronome/types/alert_archive_params.py @@ -9,3 +9,7 @@ class AlertArchiveParams(TypedDict, total=False): id: Required[str] + """The Metronome ID of the alert""" + + release_uniqueness_key: bool + """If true, resets the uniqueness key on this alert so it can be re-used""" diff --git a/src/metronome/types/alert_archive_response.py b/src/metronome/types/alert_archive_response.py index da5865ee..7f35b365 100644 --- a/src/metronome/types/alert_archive_response.py +++ b/src/metronome/types/alert_archive_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel from .shared.id import ID diff --git a/src/metronome/types/alert_create_params.py b/src/metronome/types/alert_create_params.py index affddd84..ca50caf8 100644 --- a/src/metronome/types/alert_create_params.py +++ b/src/metronome/types/alert_create_params.py @@ -33,7 +33,11 @@ class AlertCreateParams(TypedDict, total=False): """Name of the alert""" threshold: Required[float] - """Threshold value of the alert policy""" + """Threshold value of the alert policy. + + Depending upon the alert type, this number may represent a financial amount, the + days remaining, or a percentage reached. + """ billable_metric_id: str """ diff --git a/src/metronome/types/alert_create_response.py b/src/metronome/types/alert_create_response.py index eae28545..5d6f4416 100644 --- a/src/metronome/types/alert_create_response.py +++ b/src/metronome/types/alert_create_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel from .shared.id import ID diff --git a/src/metronome/types/audit_log_list_response.py b/src/metronome/types/audit_log_list_response.py index 45bfbb2e..b3ecd040 100644 --- a/src/metronome/types/audit_log_list_response.py +++ b/src/metronome/types/audit_log_list_response.py @@ -6,7 +6,15 @@ from .._models import BaseModel -__all__ = ["AuditLogListResponse", "Actor"] +__all__ = ["AuditLogListResponse", "Request", "Actor"] + + +class Request(BaseModel): + id: str + + ip: Optional[str] = None + + user_agent: Optional[str] = None class Actor(BaseModel): @@ -20,6 +28,8 @@ class Actor(BaseModel): class AuditLogListResponse(BaseModel): id: str + request: Request + timestamp: datetime action: Optional[str] = None diff --git a/src/metronome/types/billable_metric_archive_response.py b/src/metronome/types/billable_metric_archive_response.py index 00921b57..4e5fe375 100644 --- a/src/metronome/types/billable_metric_archive_response.py +++ b/src/metronome/types/billable_metric_archive_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel from .shared.id import ID diff --git a/src/metronome/types/billable_metric_create_params.py b/src/metronome/types/billable_metric_create_params.py index bd300f61..ebb0e1dd 100644 --- a/src/metronome/types/billable_metric_create_params.py +++ b/src/metronome/types/billable_metric_create_params.py @@ -12,19 +12,18 @@ class BillableMetricCreateParams(TypedDict, total=False): - aggregation_type: Required[Literal["COUNT", "LATEST", "MAX", "SUM", "UNIQUE"]] - """Specifies the type of aggregation performed on matching events.""" - name: Required[str] """The display name of the billable metric.""" aggregation_key: str - """A key that specifies which property of the event is used to aggregate data. + """Specifies the type of aggregation performed on matching events. - This key must be one of the property filter names and is not applicable when the - aggregation type is 'count'. + 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.""" @@ -44,3 +43,11 @@ class BillableMetricCreateParams(TypedDict, total=False): 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/billable_metric_create_response.py b/src/metronome/types/billable_metric_create_response.py index 3bd1952b..69796135 100644 --- a/src/metronome/types/billable_metric_create_response.py +++ b/src/metronome/types/billable_metric_create_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel from .shared.id import ID diff --git a/src/metronome/types/billable_metric_list_params.py b/src/metronome/types/billable_metric_list_params.py index 01069cb5..2e0bfe4c 100644 --- a/src/metronome/types/billable_metric_list_params.py +++ b/src/metronome/types/billable_metric_list_params.py @@ -8,6 +8,9 @@ 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""" diff --git a/src/metronome/types/billable_metric_list_response.py b/src/metronome/types/billable_metric_list_response.py index 7f906a06..7833b964 100644 --- a/src/metronome/types/billable_metric_list_response.py +++ b/src/metronome/types/billable_metric_list_response.py @@ -1,6 +1,7 @@ # 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 @@ -27,6 +28,12 @@ class BillableMetricListResponse(BaseModel): 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 event_type_filter: Optional[EventTypeFilter] = None diff --git a/src/metronome/types/billable_metric_retrieve_response.py b/src/metronome/types/billable_metric_retrieve_response.py index a4366067..1e35abfe 100644 --- a/src/metronome/types/billable_metric_retrieve_response.py +++ b/src/metronome/types/billable_metric_retrieve_response.py @@ -1,6 +1,7 @@ # 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 @@ -27,6 +28,12 @@ class Data(BaseModel): 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 event_type_filter: Optional[EventTypeFilter] = None diff --git a/src/metronome/types/contract_amend_params.py b/src/metronome/types/contract_amend_params.py index 72c4b53b..817a38b8 100644 --- a/src/metronome/types/contract_amend_params.py +++ b/src/metronome/types/contract_amend_params.py @@ -92,6 +92,7 @@ class CommitAccessSchedule(TypedDict, total=False): schedule_items: Required[Iterable[CommitAccessScheduleScheduleItem]] credit_type_id: str + """Defaults to USD (cents) if not passed""" class CommitInvoiceScheduleRecurringSchedule(TypedDict, total=False): @@ -155,7 +156,7 @@ class CommitInvoiceScheduleScheduleItem(TypedDict, total=False): class CommitInvoiceSchedule(TypedDict, total=False): credit_type_id: str - """Defaults to USD if not passed. Only USD is supported at this time.""" + """Defaults to USD (cents) if not passed.""" recurring_schedule: CommitInvoiceScheduleRecurringSchedule """Enter the unit price and quantity for the charge or instead only send the @@ -223,9 +224,17 @@ class Commit(TypedDict, total=False): first. """ + rate_type: Literal["COMMIT_RATE", "commit_rate", "LIST_RATE", "list_rate"] + rollover_fraction: float """Fraction of unused segments that will be rolled over. Must be between 0 and 1.""" + 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] @@ -241,6 +250,7 @@ class CreditAccessSchedule(TypedDict, total=False): schedule_items: Required[Iterable[CreditAccessScheduleScheduleItem]] credit_type_id: str + """Defaults to USD (cents) if not passed""" class Credit(TypedDict, total=False): @@ -280,6 +290,8 @@ class Credit(TypedDict, total=False): first. """ + rate_type: Literal["COMMIT_RATE", "commit_rate", "LIST_RATE", "list_rate"] + class DiscountScheduleRecurringSchedule(TypedDict, total=False): amount_distribution: Required[Literal["DIVIDED", "DIVIDED_ROUNDED", "EACH"]] @@ -342,7 +354,7 @@ class DiscountScheduleScheduleItem(TypedDict, total=False): class DiscountSchedule(TypedDict, total=False): credit_type_id: str - """Defaults to USD if not passed. Only USD is supported at this time.""" + """Defaults to USD (cents) if not passed.""" recurring_schedule: DiscountScheduleRecurringSchedule """Enter the unit price and quantity for the charge or instead only send the @@ -362,6 +374,8 @@ class Discount(TypedDict, total=False): schedule: Required[DiscountSchedule] """Must provide either schedule_items or recurring_schedule.""" + custom_fields: Dict[str, str] + name: str """displayed on invoices""" @@ -370,6 +384,15 @@ class Discount(TypedDict, total=False): class OverrideOverrideSpecifier(TypedDict, total=False): + commit_ids: List[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. @@ -406,7 +429,10 @@ class OverrideOverwriteRate(TypedDict, total=False): """ is_prorated: bool - """Default proration configuration. Only valid for SUBSCRIPTION rate_type.""" + """Default proration configuration. + + Only valid for SUBSCRIPTION rate_type. Must be set to true. + """ price: float """Default price. @@ -433,13 +459,25 @@ class Override(TypedDict, total=False): """RFC 3339 timestamp indicating when the override will start applying (inclusive)""" applicable_product_tags: List[str] - """tags identifying products whose rates are being overridden""" + """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.""" @@ -462,7 +500,17 @@ class Override(TypedDict, total=False): """ product_id: str - """ID of the product whose rate is being overridden""" + """ID of the product whose rate is being overridden. + + Cannot be used in conjunction with override_specifiers. + """ + + target: Literal["COMMIT_RATE", "commit_rate", "LIST_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.""" @@ -597,7 +645,7 @@ class ScheduledChargeScheduleScheduleItem(TypedDict, total=False): class ScheduledChargeSchedule(TypedDict, total=False): credit_type_id: str - """Defaults to USD if not passed. Only USD is supported at this time.""" + """Defaults to USD (cents) if not passed.""" recurring_schedule: ScheduledChargeScheduleRecurringSchedule """Enter the unit price and quantity for the charge or instead only send the diff --git a/src/metronome/types/contract_amend_response.py b/src/metronome/types/contract_amend_response.py index a53ca8d4..66523b2d 100644 --- a/src/metronome/types/contract_amend_response.py +++ b/src/metronome/types/contract_amend_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel from .shared.id import ID diff --git a/src/metronome/types/contract_archive_response.py b/src/metronome/types/contract_archive_response.py index b69f549a..02fe5eb4 100644 --- a/src/metronome/types/contract_archive_response.py +++ b/src/metronome/types/contract_archive_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel from .shared.id import ID diff --git a/src/metronome/types/contract_create_params.py b/src/metronome/types/contract_create_params.py index b206d454..883cc16d 100644 --- a/src/metronome/types/contract_create_params.py +++ b/src/metronome/types/contract_create_params.py @@ -51,7 +51,7 @@ class ContractCreateParams(TypedDict, total=False): """inclusive contract start time""" billing_provider_configuration: BillingProviderConfiguration - """This field's availability is dependent on your client's configuration.""" + """The billing provider configuration associated with a contract.""" commits: Iterable[Commit] @@ -101,6 +101,15 @@ class ContractCreateParams(TypedDict, total=False): 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. + """ + total_contract_value: float """This field's availability is dependent on your client's configuration.""" @@ -141,6 +150,7 @@ class CommitAccessSchedule(TypedDict, total=False): schedule_items: Required[Iterable[CommitAccessScheduleScheduleItem]] credit_type_id: str + """Defaults to USD (cents) if not passed""" class CommitInvoiceScheduleRecurringSchedule(TypedDict, total=False): @@ -204,7 +214,7 @@ class CommitInvoiceScheduleScheduleItem(TypedDict, total=False): class CommitInvoiceSchedule(TypedDict, total=False): credit_type_id: str - """Defaults to USD if not passed. Only USD is supported at this time.""" + """Defaults to USD (cents) if not passed.""" recurring_schedule: CommitInvoiceScheduleRecurringSchedule """Enter the unit price and quantity for the charge or instead only send the @@ -272,9 +282,17 @@ class Commit(TypedDict, total=False): first. """ + rate_type: Literal["COMMIT_RATE", "commit_rate", "LIST_RATE", "list_rate"] + rollover_fraction: float """Fraction of unused segments that will be rolled over. Must be between 0 and 1.""" + 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] @@ -290,6 +308,7 @@ class CreditAccessSchedule(TypedDict, total=False): schedule_items: Required[Iterable[CreditAccessScheduleScheduleItem]] credit_type_id: str + """Defaults to USD (cents) if not passed""" class Credit(TypedDict, total=False): @@ -329,6 +348,8 @@ class Credit(TypedDict, total=False): first. """ + rate_type: Literal["COMMIT_RATE", "commit_rate", "LIST_RATE", "list_rate"] + class DiscountScheduleRecurringSchedule(TypedDict, total=False): amount_distribution: Required[Literal["DIVIDED", "DIVIDED_ROUNDED", "EACH"]] @@ -391,7 +412,7 @@ class DiscountScheduleScheduleItem(TypedDict, total=False): class DiscountSchedule(TypedDict, total=False): credit_type_id: str - """Defaults to USD if not passed. Only USD is supported at this time.""" + """Defaults to USD (cents) if not passed.""" recurring_schedule: DiscountScheduleRecurringSchedule """Enter the unit price and quantity for the charge or instead only send the @@ -411,6 +432,8 @@ class Discount(TypedDict, total=False): schedule: Required[DiscountSchedule] """Must provide either schedule_items or recurring_schedule.""" + custom_fields: Dict[str, str] + name: str """displayed on invoices""" @@ -419,6 +442,15 @@ class Discount(TypedDict, total=False): class OverrideOverrideSpecifier(TypedDict, total=False): + commit_ids: List[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. @@ -455,7 +487,10 @@ class OverrideOverwriteRate(TypedDict, total=False): """ is_prorated: bool - """Default proration configuration. Only valid for SUBSCRIPTION rate_type.""" + """Default proration configuration. + + Only valid for SUBSCRIPTION rate_type. Must be set to true. + """ price: float """Default price. @@ -482,13 +517,25 @@ class Override(TypedDict, total=False): """RFC 3339 timestamp indicating when the override will start applying (inclusive)""" applicable_product_tags: List[str] - """tags identifying products whose rates are being overridden""" + """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.""" @@ -511,7 +558,17 @@ class Override(TypedDict, total=False): """ product_id: str - """ID of the product whose rate is being overridden""" + """ID of the product whose rate is being overridden. + + Cannot be used in conjunction with override_specifiers. + """ + + target: Literal["COMMIT_RATE", "commit_rate", "LIST_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.""" @@ -645,7 +702,7 @@ class ScheduledChargeScheduleScheduleItem(TypedDict, total=False): class ScheduledChargeSchedule(TypedDict, total=False): credit_type_id: str - """Defaults to USD if not passed. Only USD is supported at this time.""" + """Defaults to USD (cents) if not passed.""" recurring_schedule: ScheduledChargeScheduleRecurringSchedule """Enter the unit price and quantity for the charge or instead only send the @@ -690,9 +747,19 @@ class Transition(TypedDict, total=False): class UsageStatementSchedule(TypedDict, total=False): - frequency: Required[Literal["MONTHLY", "QUARTERLY"]] + frequency: Required[Literal["MONTHLY", "QUARTERLY", "ANNUAL"]] + + 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"] + day: Literal["FIRST_OF_MONTH", "CONTRACT_START", "CUSTOM_DATE", "custom_date"] """If not provided, defaults to the first day of the month.""" invoice_generation_starting_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] diff --git a/src/metronome/types/contract_create_response.py b/src/metronome/types/contract_create_response.py index 2c0547bc..35fb530a 100644 --- a/src/metronome/types/contract_create_response.py +++ b/src/metronome/types/contract_create_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel from .shared.id import ID diff --git a/src/metronome/types/contract_list_balances_params.py b/src/metronome/types/contract_list_balances_params.py index eaa945a6..541b2512 100644 --- a/src/metronome/types/contract_list_balances_params.py +++ b/src/metronome/types/contract_list_balances_params.py @@ -25,6 +25,12 @@ class ContractListBalancesParams(TypedDict, total=False): include_archived: bool """Include 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.""" diff --git a/src/metronome/types/contract_list_params.py b/src/metronome/types/contract_list_params.py index ab686dcc..360ff376 100644 --- a/src/metronome/types/contract_list_params.py +++ b/src/metronome/types/contract_list_params.py @@ -24,6 +24,12 @@ class ContractListParams(TypedDict, total=False): 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. diff --git a/src/metronome/types/contract_list_response.py b/src/metronome/types/contract_list_response.py index cf84d571..101f47f0 100644 --- a/src/metronome/types/contract_list_response.py +++ b/src/metronome/types/contract_list_response.py @@ -105,10 +105,25 @@ class Data(BaseModel): 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 customer_billing_provider_configuration: Optional[DataCustomerBillingProviderConfiguration] = None - """This field's availability is dependent on your client's configuration.""" + """The billing provider configuration associated with a contract.""" + + 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. + """ uniqueness_key: Optional[str] = None """Prevents the creation of duplicates. diff --git a/src/metronome/types/contract_retrieve_params.py b/src/metronome/types/contract_retrieve_params.py index ef77226c..98225c19 100644 --- a/src/metronome/types/contract_retrieve_params.py +++ b/src/metronome/types/contract_retrieve_params.py @@ -12,6 +12,12 @@ class ContractRetrieveParams(TypedDict, total=False): 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. diff --git a/src/metronome/types/contract_retrieve_rate_schedule_response.py b/src/metronome/types/contract_retrieve_rate_schedule_response.py index aadfb870..de049f30 100644 --- a/src/metronome/types/contract_retrieve_rate_schedule_response.py +++ b/src/metronome/types/contract_retrieve_rate_schedule_response.py @@ -2,11 +2,34 @@ 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.tier import Tier -__all__ = ["ContractRetrieveRateScheduleResponse", "Data"] +__all__ = ["ContractRetrieveRateScheduleResponse", "Data", "DataCommitRate"] + + +class DataCommitRate(BaseModel): + rate_type: Literal[ + "FLAT", + "flat", + "PERCENTAGE", + "percentage", + "SUBSCRIPTION", + "subscription", + "TIERED", + "tiered", + "CUSTOM", + "custom", + ] + + price: Optional[float] = None + """Commit rate price. For FLAT rate_type, this must be >=0.""" + + tiers: Optional[List[Tier]] = None + """Only set for TIERED rate_type.""" class Data(BaseModel): @@ -26,6 +49,13 @@ class Data(BaseModel): starting_at: datetime + commit_rate: Optional[DataCommitRate] = 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 diff --git a/src/metronome/types/contract_retrieve_response.py b/src/metronome/types/contract_retrieve_response.py index ada7a35d..8724c5c5 100644 --- a/src/metronome/types/contract_retrieve_response.py +++ b/src/metronome/types/contract_retrieve_response.py @@ -105,10 +105,25 @@ class Data(BaseModel): 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 customer_billing_provider_configuration: Optional[DataCustomerBillingProviderConfiguration] = None - """This field's availability is dependent on your client's configuration.""" + """The billing provider configuration associated with a contract.""" + + 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. + """ uniqueness_key: Optional[str] = None """Prevents the creation of duplicates. diff --git a/src/metronome/types/contract_update_end_date_params.py b/src/metronome/types/contract_update_end_date_params.py index c129d170..828faee4 100644 --- a/src/metronome/types/contract_update_end_date_params.py +++ b/src/metronome/types/contract_update_end_date_params.py @@ -18,6 +18,14 @@ class ContractUpdateEndDateParams(TypedDict, total=False): 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). diff --git a/src/metronome/types/contract_update_end_date_response.py b/src/metronome/types/contract_update_end_date_response.py index 8202d4e7..a423be61 100644 --- a/src/metronome/types/contract_update_end_date_response.py +++ b/src/metronome/types/contract_update_end_date_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel from .shared.id import ID diff --git a/src/metronome/types/contracts/product_archive_response.py b/src/metronome/types/contracts/product_archive_response.py index 1a1f5988..2d0bf3a1 100644 --- a/src/metronome/types/contracts/product_archive_response.py +++ b/src/metronome/types/contracts/product_archive_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ..._models import BaseModel from ..shared.id import ID diff --git a/src/metronome/types/contracts/product_create_params.py b/src/metronome/types/contracts/product_create_params.py index e1a9b4ef..500c634b 100644 --- a/src/metronome/types/contracts/product_create_params.py +++ b/src/metronome/types/contracts/product_create_params.py @@ -36,7 +36,7 @@ class ProductCreateParams(TypedDict, total=False): is_refundable: bool """This field's availability is dependent on your client's configuration. - Defaults to true + Defaults to true. """ netsuite_internal_item_id: str @@ -46,13 +46,20 @@ class ProductCreateParams(TypedDict, total=False): """This field's availability is dependent on your client's configuration.""" presentation_group_key: List[str] - """For USAGE products only. Groups usage line items on invoices.""" + """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: List[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. + 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] diff --git a/src/metronome/types/contracts/product_create_response.py b/src/metronome/types/contracts/product_create_response.py index 7cc7c4a2..0faeb76a 100644 --- a/src/metronome/types/contracts/product_create_response.py +++ b/src/metronome/types/contracts/product_create_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ..._models import BaseModel from ..shared.id import ID diff --git a/src/metronome/types/contracts/product_list_item_state.py b/src/metronome/types/contracts/product_list_item_state.py index 203dc887..deec790b 100755 --- a/src/metronome/types/contracts/product_list_item_state.py +++ b/src/metronome/types/contracts/product_list_item_state.py @@ -35,13 +35,20 @@ class ProductListItemState(BaseModel): """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.""" + """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. + 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 diff --git a/src/metronome/types/contracts/product_list_response.py b/src/metronome/types/contracts/product_list_response.py index eaa04c65..478053c8 100644 --- a/src/metronome/types/contracts/product_list_response.py +++ b/src/metronome/types/contracts/product_list_response.py @@ -36,13 +36,20 @@ class Update(BaseModel): """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.""" + """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. + 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 diff --git a/src/metronome/types/contracts/product_retrieve_response.py b/src/metronome/types/contracts/product_retrieve_response.py index 83370b46..be7f2317 100644 --- a/src/metronome/types/contracts/product_retrieve_response.py +++ b/src/metronome/types/contracts/product_retrieve_response.py @@ -36,13 +36,20 @@ class DataUpdate(BaseModel): """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.""" + """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. + 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 diff --git a/src/metronome/types/contracts/product_update_params.py b/src/metronome/types/contracts/product_update_params.py index 7968272f..331f0d5d 100644 --- a/src/metronome/types/contracts/product_update_params.py +++ b/src/metronome/types/contracts/product_update_params.py @@ -71,13 +71,20 @@ class ProductUpdateParams(TypedDict, total=False): """ presentation_group_key: List[str] - """For USAGE products only. Groups usage line items on invoices.""" + """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: List[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. + 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] diff --git a/src/metronome/types/contracts/product_update_response.py b/src/metronome/types/contracts/product_update_response.py index d24e7dee..13893263 100644 --- a/src/metronome/types/contracts/product_update_response.py +++ b/src/metronome/types/contracts/product_update_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ..._models import BaseModel from ..shared.id import ID diff --git a/src/metronome/types/contracts/rate_card_create_params.py b/src/metronome/types/contracts/rate_card_create_params.py index 9b037d96..9c0387c2 100644 --- a/src/metronome/types/contracts/rate_card_create_params.py +++ b/src/metronome/types/contracts/rate_card_create_params.py @@ -31,8 +31,8 @@ class RateCardCreateParams(TypedDict, total=False): 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." + The Metronome ID of the credit type to associate with the rate card, defaults to + USD (cents) if not passed. """ diff --git a/src/metronome/types/contracts/rate_card_create_response.py b/src/metronome/types/contracts/rate_card_create_response.py index 13bfc951..0869d2c6 100644 --- a/src/metronome/types/contracts/rate_card_create_response.py +++ b/src/metronome/types/contracts/rate_card_create_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ..._models import BaseModel from ..shared.id import ID diff --git a/src/metronome/types/contracts/rate_card_list_response.py b/src/metronome/types/contracts/rate_card_list_response.py index 6b654643..0c69e920 100644 --- a/src/metronome/types/contracts/rate_card_list_response.py +++ b/src/metronome/types/contracts/rate_card_list_response.py @@ -2,82 +2,11 @@ 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.credit_type import CreditType +from ..shared.credit_type_data import CreditTypeData -__all__ = [ - "RateCardListResponse", - "RateCardEntries", - "RateCardEntriesCurrent", - "RateCardEntriesUpdate", - "Alias", - "CreditTypeConversion", -] - - -class RateCardEntriesCurrent(BaseModel): - id: Optional[str] = None - - created_at: Optional[datetime] = None - - created_by: Optional[str] = None - - credit_type: Optional[CreditType] = None - - custom_rate: Optional[Dict[str, object]] = None - - ending_before: Optional[datetime] = None - - entitled: Optional[bool] = None - - price: Optional[float] = None - - product_id: Optional[str] = None - - rate_type: Optional[Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "CUSTOM", "TIERED"]] = None - - starting_at: Optional[datetime] = None - - tiers: Optional[List[Tier]] = None - - -class RateCardEntriesUpdate(BaseModel): - id: str - - created_at: datetime - - created_by: str - - entitled: bool - - product_id: str - - rate_type: Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "CUSTOM", "TIERED"] - - starting_at: datetime - - credit_type: Optional[CreditType] = None - - custom_rate: Optional[Dict[str, object]] = None - - ending_before: Optional[datetime] = None - - is_prorated: Optional[bool] = None - - price: Optional[float] = None - - quantity: Optional[float] = None - - tiers: Optional[List[Tier]] = None - - -class RateCardEntries(BaseModel): - current: Optional[RateCardEntriesCurrent] = None - - updates: Optional[List[RateCardEntriesUpdate]] = None +__all__ = ["RateCardListResponse", "Alias", "CreditTypeConversion"] class Alias(BaseModel): @@ -89,7 +18,7 @@ class Alias(BaseModel): class CreditTypeConversion(BaseModel): - custom_credit_type: CreditType + custom_credit_type: CreditTypeData fiat_per_custom_credit: str @@ -103,8 +32,6 @@ class RateCardListResponse(BaseModel): name: str - rate_card_entries: Dict[str, RateCardEntries] - aliases: Optional[List[Alias]] = None credit_type_conversions: Optional[List[CreditTypeConversion]] = None @@ -113,4 +40,4 @@ class RateCardListResponse(BaseModel): description: Optional[str] = None - fiat_credit_type: Optional[CreditType] = None + fiat_credit_type: Optional[CreditTypeData] = None diff --git a/src/metronome/types/contracts/rate_card_retrieve_rate_schedule_response.py b/src/metronome/types/contracts/rate_card_retrieve_rate_schedule_response.py index 8851f64e..79757785 100644 --- a/src/metronome/types/contracts/rate_card_retrieve_rate_schedule_response.py +++ b/src/metronome/types/contracts/rate_card_retrieve_rate_schedule_response.py @@ -2,16 +2,41 @@ 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.tier import Tier -__all__ = ["RateCardRetrieveRateScheduleResponse", "Data"] +__all__ = ["RateCardRetrieveRateScheduleResponse", "Data", "DataCommitRate"] + + +class DataCommitRate(BaseModel): + rate_type: Literal[ + "FLAT", + "flat", + "PERCENTAGE", + "percentage", + "SUBSCRIPTION", + "subscription", + "TIERED", + "tiered", + "CUSTOM", + "custom", + ] + + price: Optional[float] = None + """Commit rate price. For FLAT rate_type, this must be >=0.""" + + tiers: Optional[List[Tier]] = None + """Only set for TIERED rate_type.""" class Data(BaseModel): entitled: bool + product_custom_fields: Dict[str, str] + product_id: str product_name: str @@ -22,6 +47,13 @@ class Data(BaseModel): starting_at: datetime + commit_rate: Optional[DataCommitRate] = 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/contracts/rate_card_retrieve_response.py b/src/metronome/types/contracts/rate_card_retrieve_response.py index 6ef08927..c70f36c2 100644 --- a/src/metronome/types/contracts/rate_card_retrieve_response.py +++ b/src/metronome/types/contracts/rate_card_retrieve_response.py @@ -2,83 +2,11 @@ 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.credit_type import CreditType +from ..shared.credit_type_data import CreditTypeData -__all__ = [ - "RateCardRetrieveResponse", - "Data", - "DataRateCardEntries", - "DataRateCardEntriesCurrent", - "DataRateCardEntriesUpdate", - "DataAlias", - "DataCreditTypeConversion", -] - - -class DataRateCardEntriesCurrent(BaseModel): - id: Optional[str] = None - - created_at: Optional[datetime] = None - - created_by: Optional[str] = None - - credit_type: Optional[CreditType] = None - - custom_rate: Optional[Dict[str, object]] = None - - ending_before: Optional[datetime] = None - - entitled: Optional[bool] = None - - price: Optional[float] = None - - product_id: Optional[str] = None - - rate_type: Optional[Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "CUSTOM", "TIERED"]] = None - - starting_at: Optional[datetime] = None - - tiers: Optional[List[Tier]] = None - - -class DataRateCardEntriesUpdate(BaseModel): - id: str - - created_at: datetime - - created_by: str - - entitled: bool - - product_id: str - - rate_type: Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "CUSTOM", "TIERED"] - - starting_at: datetime - - credit_type: Optional[CreditType] = None - - custom_rate: Optional[Dict[str, object]] = None - - ending_before: Optional[datetime] = None - - is_prorated: Optional[bool] = None - - price: Optional[float] = None - - quantity: Optional[float] = None - - tiers: Optional[List[Tier]] = None - - -class DataRateCardEntries(BaseModel): - current: Optional[DataRateCardEntriesCurrent] = None - - updates: Optional[List[DataRateCardEntriesUpdate]] = None +__all__ = ["RateCardRetrieveResponse", "Data", "DataAlias", "DataCreditTypeConversion"] class DataAlias(BaseModel): @@ -90,7 +18,7 @@ class DataAlias(BaseModel): class DataCreditTypeConversion(BaseModel): - custom_credit_type: CreditType + custom_credit_type: CreditTypeData fiat_per_custom_credit: str @@ -104,8 +32,6 @@ class Data(BaseModel): name: str - rate_card_entries: Dict[str, DataRateCardEntries] - aliases: Optional[List[DataAlias]] = None credit_type_conversions: Optional[List[DataCreditTypeConversion]] = None @@ -114,7 +40,7 @@ class Data(BaseModel): description: Optional[str] = None - fiat_credit_type: Optional[CreditType] = None + fiat_credit_type: Optional[CreditTypeData] = None class RateCardRetrieveResponse(BaseModel): diff --git a/src/metronome/types/contracts/rate_card_update_params.py b/src/metronome/types/contracts/rate_card_update_params.py index 51726673..e51a6ef8 100644 --- a/src/metronome/types/contracts/rate_card_update_params.py +++ b/src/metronome/types/contracts/rate_card_update_params.py @@ -2,7 +2,7 @@ from __future__ import annotations -from typing import Dict, Union, Iterable +from typing import Union, Iterable from datetime import datetime from typing_extensions import Required, Annotated, TypedDict @@ -22,8 +22,6 @@ class RateCardUpdateParams(TypedDict, total=False): card to which it was most recently assigned. It is not exposed to end customers. """ - custom_fields: Dict[str, str] - description: str name: str diff --git a/src/metronome/types/contracts/rate_card_update_response.py b/src/metronome/types/contracts/rate_card_update_response.py index b767da00..d41dbfd0 100644 --- a/src/metronome/types/contracts/rate_card_update_response.py +++ b/src/metronome/types/contracts/rate_card_update_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ..._models import BaseModel from ..shared.id import ID diff --git a/src/metronome/types/contracts/rate_cards/product_order_set_response.py b/src/metronome/types/contracts/rate_cards/product_order_set_response.py index 1466715b..a8f8e0e2 100644 --- a/src/metronome/types/contracts/rate_cards/product_order_set_response.py +++ b/src/metronome/types/contracts/rate_cards/product_order_set_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ...._models import BaseModel from ...shared.id import ID diff --git a/src/metronome/types/contracts/rate_cards/product_order_update_response.py b/src/metronome/types/contracts/rate_cards/product_order_update_response.py index 618f42ea..28d5289e 100644 --- a/src/metronome/types/contracts/rate_cards/product_order_update_response.py +++ b/src/metronome/types/contracts/rate_cards/product_order_update_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ...._models import BaseModel from ...shared.id import ID diff --git a/src/metronome/types/contracts/rate_cards/rate_add_many_params.py b/src/metronome/types/contracts/rate_cards/rate_add_many_params.py index 2cf2d466..d124d5b4 100644 --- a/src/metronome/types/contracts/rate_cards/rate_add_many_params.py +++ b/src/metronome/types/contracts/rate_cards/rate_add_many_params.py @@ -9,13 +9,36 @@ from ...._utils import PropertyInfo from ...shared_params.tier import Tier -__all__ = ["RateAddManyParams", "Rate"] +__all__ = ["RateAddManyParams", "Rate", "RateCommitRate"] class RateAddManyParams(TypedDict, total=False): - rate_card_id: str + rate_card_id: Required[str] + + rates: Required[Iterable[Rate]] + + +class RateCommitRate(TypedDict, total=False): + rate_type: Required[ + Literal[ + "FLAT", + "flat", + "PERCENTAGE", + "percentage", + "SUBSCRIPTION", + "subscription", + "TIERED", + "tiered", + "CUSTOM", + "custom", + ] + ] - rates: Iterable[Rate] + price: float + """Commit rate price. For FLAT rate_type, this must be >=0.""" + + tiers: Iterable[Tier] + """Only set for TIERED rate_type.""" class Rate(TypedDict, total=False): @@ -29,6 +52,13 @@ class Rate(TypedDict, total=False): starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] """inclusive effective date""" + commit_rate: RateCommitRate + """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 @@ -46,7 +76,10 @@ class Rate(TypedDict, total=False): """exclusive end date""" is_prorated: bool - """Default proration configuration. Only valid for SUBSCRIPTION rate_type.""" + """Default proration configuration. + + Only valid for SUBSCRIPTION rate_type. Must be set to true. + """ price: float """Default price. diff --git a/src/metronome/types/contracts/rate_cards/rate_add_many_response.py b/src/metronome/types/contracts/rate_cards/rate_add_many_response.py index ca920d10..f6aa3408 100644 --- a/src/metronome/types/contracts/rate_cards/rate_add_many_response.py +++ b/src/metronome/types/contracts/rate_cards/rate_add_many_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ...._models import BaseModel from ...shared.id import ID diff --git a/src/metronome/types/contracts/rate_cards/rate_add_params.py b/src/metronome/types/contracts/rate_cards/rate_add_params.py index d981ab17..ddb8d072 100644 --- a/src/metronome/types/contracts/rate_cards/rate_add_params.py +++ b/src/metronome/types/contracts/rate_cards/rate_add_params.py @@ -9,7 +9,7 @@ from ...._utils import PropertyInfo from ...shared_params.tier import Tier -__all__ = ["RateAddParams"] +__all__ = ["RateAddParams", "CommitRate"] class RateAddParams(TypedDict, total=False): @@ -26,11 +26,18 @@ class RateAddParams(TypedDict, total=False): starting_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] """inclusive effective date""" + 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 + 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." + rates use the credit type of associated rates. """ custom_rate: Dict[str, object] @@ -43,7 +50,10 @@ class RateAddParams(TypedDict, total=False): """exclusive end date""" is_prorated: bool - """Default proration configuration. Only valid for SUBSCRIPTION rate_type.""" + """Default proration configuration. + + Only valid for SUBSCRIPTION rate_type. Must be set to true. + """ price: float """Default price. @@ -70,3 +80,26 @@ class RateAddParams(TypedDict, total=False): Defaults to false. If true, rate is computed using list prices rather than the standard rates for this product on the contract. """ + + +class CommitRate(TypedDict, total=False): + rate_type: Required[ + Literal[ + "FLAT", + "flat", + "PERCENTAGE", + "percentage", + "SUBSCRIPTION", + "subscription", + "TIERED", + "tiered", + "CUSTOM", + "custom", + ] + ] + + price: float + """Commit rate price. For FLAT rate_type, this must be >=0.""" + + tiers: Iterable[Tier] + """Only set for TIERED rate_type.""" diff --git a/src/metronome/types/contracts/rate_cards/rate_add_response.py b/src/metronome/types/contracts/rate_cards/rate_add_response.py index ffebea6c..a198fc93 100644 --- a/src/metronome/types/contracts/rate_cards/rate_add_response.py +++ b/src/metronome/types/contracts/rate_cards/rate_add_response.py @@ -1,12 +1,97 @@ # 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.rate import Rate +from ...shared.tier import Tier +from ...shared.credit_type_data import CreditTypeData + +__all__ = ["RateAddResponse", "Data", "DataCommitRate"] + + +class DataCommitRate(BaseModel): + rate_type: Literal[ + "FLAT", + "flat", + "PERCENTAGE", + "percentage", + "SUBSCRIPTION", + "subscription", + "TIERED", + "tiered", + "CUSTOM", + "custom", + ] + + price: Optional[float] = None + """Commit rate price. For FLAT rate_type, this must be >=0.""" + + tiers: Optional[List[Tier]] = None + """Only set for TIERED rate_type.""" + + +class Data(BaseModel): + rate_type: Literal[ + "FLAT", + "flat", + "PERCENTAGE", + "percentage", + "SUBSCRIPTION", + "subscription", + "CUSTOM", + "custom", + "TIERED", + "tiered", + ] + + commit_rate: Optional[DataCommitRate] = 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.""" + + use_list_prices: Optional[bool] = None + """Only set for PERCENTAGE rate_type. -__all__ = ["RateAddResponse"] + Defaults to false. If true, rate is computed using list prices rather than the + standard rates for this product on the contract. + """ class RateAddResponse(BaseModel): - data: Rate + data: Data diff --git a/src/metronome/types/contracts/rate_cards/rate_list_response.py b/src/metronome/types/contracts/rate_cards/rate_list_response.py index 3d2d807a..29fe3c0b 100644 --- a/src/metronome/types/contracts/rate_cards/rate_list_response.py +++ b/src/metronome/types/contracts/rate_cards/rate_list_response.py @@ -2,16 +2,41 @@ 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.tier import Tier -__all__ = ["RateListResponse"] +__all__ = ["RateListResponse", "CommitRate"] + + +class CommitRate(BaseModel): + rate_type: Literal[ + "FLAT", + "flat", + "PERCENTAGE", + "percentage", + "SUBSCRIPTION", + "subscription", + "TIERED", + "tiered", + "CUSTOM", + "custom", + ] + + price: Optional[float] = None + """Commit rate price. For FLAT rate_type, this must be >=0.""" + + tiers: Optional[List[Tier]] = None + """Only set for TIERED rate_type.""" class RateListResponse(BaseModel): entitled: bool + product_custom_fields: Dict[str, str] + product_id: str product_name: str @@ -22,6 +47,13 @@ class RateListResponse(BaseModel): starting_at: datetime + 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/credit_grant_create_params.py b/src/metronome/types/credit_grant_create_params.py index a4dcc25a..806aa924 100644 --- a/src/metronome/types/credit_grant_create_params.py +++ b/src/metronome/types/credit_grant_create_params.py @@ -19,8 +19,7 @@ class CreditGrantCreateParams(TypedDict, total=False): expires_at: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] """ - The credit grant will only apply to billing periods that end before this - timestamp. + The credit grant will only apply to usage or charges dated before this timestamp """ grant_amount: Required[GrantAmount] @@ -41,8 +40,8 @@ class CreditGrantCreateParams(TypedDict, total=False): effective_at: Annotated[Union[str, datetime], PropertyInfo(format="iso8601")] """ - The credit grant will only apply to billing periods that end at or after this - timestamp. + 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")] @@ -77,12 +76,14 @@ class GrantAmount(TypedDict, total=False): 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): 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] diff --git a/src/metronome/types/credit_grant_create_response.py b/src/metronome/types/credit_grant_create_response.py index 2f2548d5..275dbdd4 100644 --- a/src/metronome/types/credit_grant_create_response.py +++ b/src/metronome/types/credit_grant_create_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel from .shared.id import ID diff --git a/src/metronome/types/credit_grant_edit_response.py b/src/metronome/types/credit_grant_edit_response.py index 48cb4e93..ca73d591 100644 --- a/src/metronome/types/credit_grant_edit_response.py +++ b/src/metronome/types/credit_grant_edit_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel from .shared.id import ID diff --git a/src/metronome/types/credit_grant_list_entries_response.py b/src/metronome/types/credit_grant_list_entries_response.py index 5e6231fb..2b13ab56 100644 --- a/src/metronome/types/credit_grant_list_entries_response.py +++ b/src/metronome/types/credit_grant_list_entries_response.py @@ -4,8 +4,8 @@ from datetime import datetime from .._models import BaseModel -from .shared.credit_type import CreditType from .credit_ledger_entry import CreditLedgerEntry +from .shared.credit_type_data import CreditTypeData __all__ = [ "CreditGrantListEntriesResponse", @@ -58,7 +58,7 @@ class DataLedgerStartingBalance(BaseModel): class DataLedger(BaseModel): - credit_type: CreditType + credit_type: CreditTypeData ending_balance: DataLedgerEndingBalance """the effective balances at the end of the specified time window""" diff --git a/src/metronome/types/credit_grant_list_response.py b/src/metronome/types/credit_grant_list_response.py index 497a88bb..d2514dbe 100644 --- a/src/metronome/types/credit_grant_list_response.py +++ b/src/metronome/types/credit_grant_list_response.py @@ -4,8 +4,8 @@ from datetime import datetime from .._models import BaseModel -from .shared.credit_type import CreditType from .credit_ledger_entry import CreditLedgerEntry +from .shared.credit_type_data import CreditTypeData __all__ = ["CreditGrantListResponse", "Balance", "GrantAmount", "PaidAmount", "Product"] @@ -31,14 +31,14 @@ class Balance(BaseModel): class GrantAmount(BaseModel): amount: float - credit_type: CreditType + credit_type: CreditTypeData """the credit type for the amount granted""" class PaidAmount(BaseModel): amount: float - credit_type: CreditType + credit_type: CreditTypeData """the credit type for the amount paid""" diff --git a/src/metronome/types/credit_grant_void_response.py b/src/metronome/types/credit_grant_void_response.py index b1a751ed..9b8f4b3d 100644 --- a/src/metronome/types/credit_grant_void_response.py +++ b/src/metronome/types/credit_grant_void_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel from .shared.id import ID diff --git a/src/metronome/types/custom_field_add_key_params.py b/src/metronome/types/custom_field_add_key_params.py index 6269b33b..b150be0f 100644 --- a/src/metronome/types/custom_field_add_key_params.py +++ b/src/metronome/types/custom_field_add_key_params.py @@ -22,6 +22,7 @@ class CustomFieldAddKeyParams(TypedDict, total=False): "credit_grant", "customer_plan", "customer", + "discount", "invoice", "plan", "professional_service", diff --git a/src/metronome/types/custom_field_delete_values_params.py b/src/metronome/types/custom_field_delete_values_params.py index 4c9fa07d..459f120c 100644 --- a/src/metronome/types/custom_field_delete_values_params.py +++ b/src/metronome/types/custom_field_delete_values_params.py @@ -21,6 +21,7 @@ class CustomFieldDeleteValuesParams(TypedDict, total=False): "credit_grant", "customer_plan", "customer", + "discount", "invoice", "plan", "professional_service", diff --git a/src/metronome/types/custom_field_list_keys_params.py b/src/metronome/types/custom_field_list_keys_params.py index 9af74d77..3d0847c5 100644 --- a/src/metronome/types/custom_field_list_keys_params.py +++ b/src/metronome/types/custom_field_list_keys_params.py @@ -24,6 +24,7 @@ class CustomFieldListKeysParams(TypedDict, total=False): "credit_grant", "customer_plan", "customer", + "discount", "invoice", "plan", "professional_service", diff --git a/src/metronome/types/custom_field_list_keys_response.py b/src/metronome/types/custom_field_list_keys_response.py index 290651ec..db5ac975 100644 --- a/src/metronome/types/custom_field_list_keys_response.py +++ b/src/metronome/types/custom_field_list_keys_response.py @@ -22,6 +22,7 @@ class Data(BaseModel): "credit_grant", "customer_plan", "customer", + "discount", "invoice", "plan", "professional_service", diff --git a/src/metronome/types/custom_field_remove_key_params.py b/src/metronome/types/custom_field_remove_key_params.py index ec0036d4..ab641588 100644 --- a/src/metronome/types/custom_field_remove_key_params.py +++ b/src/metronome/types/custom_field_remove_key_params.py @@ -20,6 +20,7 @@ class CustomFieldRemoveKeyParams(TypedDict, total=False): "credit_grant", "customer_plan", "customer", + "discount", "invoice", "plan", "professional_service", diff --git a/src/metronome/types/custom_field_set_values_params.py b/src/metronome/types/custom_field_set_values_params.py index 949d6f75..155914e1 100644 --- a/src/metronome/types/custom_field_set_values_params.py +++ b/src/metronome/types/custom_field_set_values_params.py @@ -23,6 +23,7 @@ class CustomFieldSetValuesParams(TypedDict, total=False): "credit_grant", "customer_plan", "customer", + "discount", "invoice", "plan", "professional_service", diff --git a/src/metronome/types/customer_archive_response.py b/src/metronome/types/customer_archive_response.py index 64e4950b..816aa24a 100644 --- a/src/metronome/types/customer_archive_response.py +++ b/src/metronome/types/customer_archive_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel from .shared.id import ID diff --git a/src/metronome/types/customer_create_params.py b/src/metronome/types/customer_create_params.py index 28b1c792..7be72bb1 100644 --- a/src/metronome/types/customer_create_params.py +++ b/src/metronome/types/customer_create_params.py @@ -2,10 +2,10 @@ from __future__ import annotations -from typing import Dict, List +from typing import Dict, List, Iterable from typing_extensions import Literal, Required, TypedDict -__all__ = ["CustomerCreateParams", "BillingConfig"] +__all__ = ["CustomerCreateParams", "BillingConfig", "CustomerBillingProviderConfiguration"] class CustomerCreateParams(TypedDict, total=False): @@ -16,10 +16,12 @@ class CustomerCreateParams(TypedDict, total=False): custom_fields: Dict[str, str] + customer_billing_provider_configurations: Iterable[CustomerBillingProviderConfiguration] + external_id: str """ - (deprecated, use ingest_aliases instead) the first ID (Metronome ID or ingest - alias) that can be used in usage events + (deprecated, use ingest_aliases instead) an alias that can be used to refer to + this customer in usage events """ ingest_aliases: List[str] @@ -42,6 +44,9 @@ class BillingConfig(TypedDict, total=False): ] ] + 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[ @@ -73,3 +78,28 @@ class BillingConfig(TypedDict, total=False): ] stripe_collection_method: Literal["charge_automatically", "send_invoice"] + + +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. + """ diff --git a/src/metronome/types/customer_create_response.py b/src/metronome/types/customer_create_response.py index 049fdc95..672f3ee6 100644 --- a/src/metronome/types/customer_create_response.py +++ b/src/metronome/types/customer_create_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel from .customer import Customer diff --git a/src/metronome/types/customer_list_billable_metrics_params.py b/src/metronome/types/customer_list_billable_metrics_params.py index d187c1a3..1b1e22f6 100644 --- a/src/metronome/types/customer_list_billable_metrics_params.py +++ b/src/metronome/types/customer_list_billable_metrics_params.py @@ -2,12 +2,17 @@ from __future__ import annotations -from typing_extensions import TypedDict +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""" diff --git a/src/metronome/types/customer_list_billable_metrics_response.py b/src/metronome/types/customer_list_billable_metrics_response.py index 4ecd0045..19fd8738 100644 --- a/src/metronome/types/customer_list_billable_metrics_response.py +++ b/src/metronome/types/customer_list_billable_metrics_response.py @@ -1,6 +1,7 @@ # 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 @@ -31,6 +32,12 @@ class CustomerListBillableMetricsResponse(BaseModel): 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 event_type_filter: Optional[EventTypeFilter] = None diff --git a/src/metronome/types/customer_list_costs_params.py b/src/metronome/types/customer_list_costs_params.py index c93a7ebb..3baacfe2 100644 --- a/src/metronome/types/customer_list_costs_params.py +++ b/src/metronome/types/customer_list_costs_params.py @@ -12,6 +12,8 @@ class CustomerListCostsParams(TypedDict, total=False): + customer_id: Required[str] + ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] """RFC 3339 timestamp (exclusive)""" diff --git a/src/metronome/types/customer_retrieve_response.py b/src/metronome/types/customer_retrieve_response.py index 4e6965b5..a1382e09 100644 --- a/src/metronome/types/customer_retrieve_response.py +++ b/src/metronome/types/customer_retrieve_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel from .customer_detail import CustomerDetail diff --git a/src/metronome/types/customer_set_ingest_aliases_params.py b/src/metronome/types/customer_set_ingest_aliases_params.py index cdb01bc5..3db48a78 100644 --- a/src/metronome/types/customer_set_ingest_aliases_params.py +++ b/src/metronome/types/customer_set_ingest_aliases_params.py @@ -9,4 +9,6 @@ class CustomerSetIngestAliasesParams(TypedDict, total=False): + customer_id: Required[str] + ingest_aliases: Required[List[str]] diff --git a/src/metronome/types/customer_set_name_params.py b/src/metronome/types/customer_set_name_params.py index 21f90af7..f95821f4 100644 --- a/src/metronome/types/customer_set_name_params.py +++ b/src/metronome/types/customer_set_name_params.py @@ -8,6 +8,8 @@ class CustomerSetNameParams(TypedDict, total=False): + customer_id: Required[str] + name: Required[str] """The new name for the customer. diff --git a/src/metronome/types/customer_set_name_response.py b/src/metronome/types/customer_set_name_response.py index 9be9006a..79727df3 100644 --- a/src/metronome/types/customer_set_name_response.py +++ b/src/metronome/types/customer_set_name_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel from .customer import Customer diff --git a/src/metronome/types/customer_update_config_params.py b/src/metronome/types/customer_update_config_params.py index eb28d0df..9f0ae706 100644 --- a/src/metronome/types/customer_update_config_params.py +++ b/src/metronome/types/customer_update_config_params.py @@ -3,12 +3,14 @@ from __future__ import annotations from typing import Optional -from typing_extensions import TypedDict +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. diff --git a/src/metronome/types/customers/alert_retrieve_response.py b/src/metronome/types/customers/alert_retrieve_response.py index 2055f8b4..91ccf04e 100644 --- a/src/metronome/types/customers/alert_retrieve_response.py +++ b/src/metronome/types/customers/alert_retrieve_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ..._models import BaseModel from .customer_alert import CustomerAlert diff --git a/src/metronome/types/customers/billing_config_create_params.py b/src/metronome/types/customers/billing_config_create_params.py index 75ec0457..856e4de2 100644 --- a/src/metronome/types/customers/billing_config_create_params.py +++ b/src/metronome/types/customers/billing_config_create_params.py @@ -10,6 +10,19 @@ 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", + ] + ] + billing_provider_customer_id: Required[str] """The customer ID in the billing provider's system. diff --git a/src/metronome/types/customers/billing_config_retrieve_response.py b/src/metronome/types/customers/billing_config_retrieve_response.py index 931515ef..509527a7 100644 --- a/src/metronome/types/customers/billing_config_retrieve_response.py +++ b/src/metronome/types/customers/billing_config_retrieve_response.py @@ -13,9 +13,8 @@ class Data(BaseModel): 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. (See - https://docs.aws.amazon.com/marketplaceentitlement/latest/APIReference/API_GetEntitlements.html.) + 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_product_code: Optional[str] = None @@ -53,9 +52,8 @@ class Data(BaseModel): 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. (See - https://learn.microsoft.com/en-us/partner-center/marketplace/partner-center-portal/pc-saas-fulfillment-subscription-api#get-subscription.) + 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 @@ -63,9 +61,8 @@ class Data(BaseModel): 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. (See - https://learn.microsoft.com/en-us/partner-center/marketplace/partner-center-portal/pc-saas-fulfillment-subscription-api#get-subscription.) + 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[ diff --git a/src/metronome/types/customers/commit_create_params.py b/src/metronome/types/customers/commit_create_params.py index bba3616a..77182233 100644 --- a/src/metronome/types/customers/commit_create_params.py +++ b/src/metronome/types/customers/commit_create_params.py @@ -35,6 +35,10 @@ class CommitCreateParams(TypedDict, total=False): """ 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"]] @@ -84,9 +88,19 @@ class CommitCreateParams(TypedDict, total=False): netsuite_sales_order_id: str """This field's availability is dependent on your client's configuration.""" + rate_type: Literal["COMMIT_RATE", "commit_rate", "LIST_RATE", "list_rate"] + salesforce_opportunity_id: str """This field's availability is dependent on your client's configuration.""" + 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] @@ -102,6 +116,7 @@ class AccessSchedule(TypedDict, total=False): schedule_items: Required[Iterable[AccessScheduleScheduleItem]] credit_type_id: str + """Defaults to USD (cents) if not passed""" class InvoiceScheduleRecurringSchedule(TypedDict, total=False): @@ -165,7 +180,7 @@ class InvoiceScheduleScheduleItem(TypedDict, total=False): class InvoiceSchedule(TypedDict, total=False): credit_type_id: str - """Defaults to USD if not passed. Only USD is supported at this time.""" + """Defaults to USD (cents) if not passed.""" recurring_schedule: InvoiceScheduleRecurringSchedule """Enter the unit price and quantity for the charge or instead only send the diff --git a/src/metronome/types/customers/commit_create_response.py b/src/metronome/types/customers/commit_create_response.py index 1cafdec5..a7401af2 100644 --- a/src/metronome/types/customers/commit_create_response.py +++ b/src/metronome/types/customers/commit_create_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ..._models import BaseModel from ..shared.id import ID diff --git a/src/metronome/types/customers/commit_list_params.py b/src/metronome/types/customers/commit_list_params.py index 0af6498b..d5897faf 100644 --- a/src/metronome/types/customers/commit_list_params.py +++ b/src/metronome/types/customers/commit_list_params.py @@ -25,6 +25,12 @@ class CommitListParams(TypedDict, total=False): include_archived: bool """Include 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.""" diff --git a/src/metronome/types/customers/commit_update_end_date_response.py b/src/metronome/types/customers/commit_update_end_date_response.py index 544a7ab2..cbe3d581 100644 --- a/src/metronome/types/customers/commit_update_end_date_response.py +++ b/src/metronome/types/customers/commit_update_end_date_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ..._models import BaseModel from ..shared.id import ID diff --git a/src/metronome/types/customers/credit_create_params.py b/src/metronome/types/customers/credit_create_params.py index 93960aac..296cf489 100644 --- a/src/metronome/types/customers/credit_create_params.py +++ b/src/metronome/types/customers/credit_create_params.py @@ -4,7 +4,7 @@ from typing import Dict, List, Union, Iterable from datetime import datetime -from typing_extensions import Required, Annotated, TypedDict +from typing_extensions import Literal, Required, Annotated, TypedDict from ..._utils import PropertyInfo @@ -56,9 +56,19 @@ class CreditCreateParams(TypedDict, total=False): netsuite_sales_order_id: str """This field's availability is dependent on your client's configuration.""" + rate_type: Literal["COMMIT_RATE", "commit_rate", "LIST_RATE", "list_rate"] + salesforce_opportunity_id: str """This field's availability is dependent on your client's configuration.""" + 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] @@ -74,3 +84,4 @@ class AccessSchedule(TypedDict, total=False): schedule_items: Required[Iterable[AccessScheduleScheduleItem]] credit_type_id: str + """Defaults to USD (cents) if not passed""" diff --git a/src/metronome/types/customers/credit_create_response.py b/src/metronome/types/customers/credit_create_response.py index 9debbee7..09775523 100644 --- a/src/metronome/types/customers/credit_create_response.py +++ b/src/metronome/types/customers/credit_create_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ..._models import BaseModel from ..shared.id import ID diff --git a/src/metronome/types/customers/credit_list_params.py b/src/metronome/types/customers/credit_list_params.py index d3a86bb4..541f9145 100644 --- a/src/metronome/types/customers/credit_list_params.py +++ b/src/metronome/types/customers/credit_list_params.py @@ -25,6 +25,12 @@ class CreditListParams(TypedDict, total=False): include_archived: bool """Include 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.""" diff --git a/src/metronome/types/customers/credit_update_end_date_response.py b/src/metronome/types/customers/credit_update_end_date_response.py index 40cfacfc..53f85224 100644 --- a/src/metronome/types/customers/credit_update_end_date_response.py +++ b/src/metronome/types/customers/credit_update_end_date_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ..._models import BaseModel from ..shared.id import ID diff --git a/src/metronome/types/customers/customer_alert.py b/src/metronome/types/customers/customer_alert.py index 96ad50f5..bbf9c4e3 100644 --- a/src/metronome/types/customers/customer_alert.py +++ b/src/metronome/types/customers/customer_alert.py @@ -5,7 +5,7 @@ from typing_extensions import Literal from ..._models import BaseModel -from ..shared.credit_type import CreditType +from ..shared.credit_type_data import CreditTypeData __all__ = ["CustomerAlert", "Alert", "AlertCustomFieldFilter", "AlertGroupKeyFilter"] @@ -65,7 +65,7 @@ class Alert(BaseModel): field is only defined for CreditPercentage and CreditBalance alerts """ - credit_type: Optional[CreditType] = None + credit_type: Optional[CreditTypeData] = None custom_field_filters: Optional[List[AlertCustomFieldFilter]] = None """A list of custom field filters for alert types that support advanced filtering""" diff --git a/src/metronome/types/customers/invoice.py b/src/metronome/types/customers/invoice.py index 44b76278..7ef681b6 100644 --- a/src/metronome/types/customers/invoice.py +++ b/src/metronome/types/customers/invoice.py @@ -6,15 +6,17 @@ from ..._models import BaseModel from ..shared.rate import Rate -from ..shared.credit_type import CreditType +from ..shared.credit_type_data import CreditTypeData __all__ = [ "Invoice", "LineItem", + "LineItemAppliedCommitOrCredit", "LineItemPostpaidCommit", "LineItemSubLineItem", "LineItemSubLineItemTierPeriod", "LineItemSubLineItemTier", + "LineItemTier", "CorrectionRecord", "CorrectionRecordCorrectedExternalInvoice", "ExternalInvoice", @@ -25,6 +27,12 @@ ] +class LineItemAppliedCommitOrCredit(BaseModel): + id: str + + type: Literal["PREPAID", "POSTPAID", "CREDIT"] + + class LineItemPostpaidCommit(BaseModel): id: str @@ -77,14 +85,26 @@ class LineItemSubLineItem(BaseModel): tiers: Optional[List[LineItemSubLineItemTier]] = None +class LineItemTier(BaseModel): + level: float + + starting_at: str + + size: Optional[str] = None + + class LineItem(BaseModel): - credit_type: CreditType + credit_type: CreditTypeData name: str total: float + applied_commit_or_credit: Optional[LineItemAppliedCommitOrCredit] = None + """only present for beta contract invoices""" + commit_custom_fields: Optional[Dict[str, str]] = None + """only present for beta contract invoices""" commit_id: Optional[str] = None """only present for beta contract invoices""" @@ -121,7 +141,7 @@ class LineItem(BaseModel): list_price: Optional[Rate] = None """ - only present for contract invoices and when the include_list_prices query + 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. """ @@ -162,6 +182,7 @@ class LineItem(BaseModel): product_type: Optional[str] = None professional_service_custom_fields: Optional[Dict[str, str]] = None + """only present for beta contract invoices""" professional_service_id: Optional[str] = None """only present for beta contract invoices""" @@ -180,6 +201,8 @@ class LineItem(BaseModel): sub_line_items: Optional[List[LineItemSubLineItem]] = None + tier: Optional[LineItemTier] = None + unit_price: Optional[float] = None """only present for beta contract invoices""" @@ -261,7 +284,7 @@ class ExternalInvoice(BaseModel): class InvoiceAdjustment(BaseModel): - credit_type: CreditType + credit_type: CreditTypeData name: str @@ -301,7 +324,7 @@ class ResellerRoyalty(BaseModel): class Invoice(BaseModel): id: str - credit_type: CreditType + credit_type: CreditTypeData customer_id: str diff --git a/src/metronome/types/customers/invoice_add_charge_params.py b/src/metronome/types/customers/invoice_add_charge_params.py index 42668cdf..335e633d 100644 --- a/src/metronome/types/customers/invoice_add_charge_params.py +++ b/src/metronome/types/customers/invoice_add_charge_params.py @@ -12,6 +12,8 @@ class InvoiceAddChargeParams(TypedDict, total=False): + customer_id: Required[str] + charge_id: Required[str] """The Metronome ID of the charge to add to the invoice. diff --git a/src/metronome/types/customers/invoice_add_charge_response.py b/src/metronome/types/customers/invoice_add_charge_response.py index 173ddcf8..056fcf36 100644 --- a/src/metronome/types/customers/invoice_add_charge_response.py +++ b/src/metronome/types/customers/invoice_add_charge_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ..._models import BaseModel __all__ = ["InvoiceAddChargeResponse"] diff --git a/src/metronome/types/customers/invoice_list_breakdowns_params.py b/src/metronome/types/customers/invoice_list_breakdowns_params.py index be90c5a0..9b2c66e5 100644 --- a/src/metronome/types/customers/invoice_list_breakdowns_params.py +++ b/src/metronome/types/customers/invoice_list_breakdowns_params.py @@ -12,6 +12,8 @@ class InvoiceListBreakdownsParams(TypedDict, total=False): + customer_id: Required[str] + ending_before: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] """RFC 3339 timestamp. diff --git a/src/metronome/types/customers/invoice_list_params.py b/src/metronome/types/customers/invoice_list_params.py index 4f386d7e..cc330a48 100644 --- a/src/metronome/types/customers/invoice_list_params.py +++ b/src/metronome/types/customers/invoice_list_params.py @@ -4,7 +4,7 @@ from typing import Union from datetime import datetime -from typing_extensions import Literal, Annotated, TypedDict +from typing_extensions import Literal, Required, Annotated, TypedDict from ..._utils import PropertyInfo @@ -12,6 +12,8 @@ class InvoiceListParams(TypedDict, total=False): + customer_id: Required[str] + credit_type_id: str """Only return invoices for the specified credit type""" diff --git a/src/metronome/types/customers/invoice_retrieve_params.py b/src/metronome/types/customers/invoice_retrieve_params.py index a19d0ec2..c1fad581 100644 --- a/src/metronome/types/customers/invoice_retrieve_params.py +++ b/src/metronome/types/customers/invoice_retrieve_params.py @@ -10,5 +10,7 @@ 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/customers/invoice_retrieve_response.py b/src/metronome/types/customers/invoice_retrieve_response.py index 7a8310f1..32df2ee6 100644 --- a/src/metronome/types/customers/invoice_retrieve_response.py +++ b/src/metronome/types/customers/invoice_retrieve_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .invoice import Invoice from ..._models import BaseModel diff --git a/src/metronome/types/customers/plan_add_params.py b/src/metronome/types/customers/plan_add_params.py index 0d004802..ec89ca93 100644 --- a/src/metronome/types/customers/plan_add_params.py +++ b/src/metronome/types/customers/plan_add_params.py @@ -12,6 +12,8 @@ class PlanAddParams(TypedDict, total=False): + customer_id: Required[str] + plan_id: Required[str] starting_on: Required[Annotated[Union[str, datetime], PropertyInfo(format="iso8601")]] @@ -42,7 +44,7 @@ class PlanAddParams(TypedDict, total=False): """A list of price adjustments can be applied on top of the pricing in the plans. See the - [price adjustments documentation](https://docs.metronome.com/pricing/managing-plans/#price-adjustments) + [price adjustments documentation](https://plans-docs.metronome.com/pricing/managing-plans/#price-adjustments) for details. """ diff --git a/src/metronome/types/customers/plan_add_response.py b/src/metronome/types/customers/plan_add_response.py index aa4ff08b..8aac3b39 100644 --- a/src/metronome/types/customers/plan_add_response.py +++ b/src/metronome/types/customers/plan_add_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ..._models import BaseModel from ..shared.id import ID diff --git a/src/metronome/types/customers/plan_end_params.py b/src/metronome/types/customers/plan_end_params.py index b808e4a6..886f6782 100644 --- a/src/metronome/types/customers/plan_end_params.py +++ b/src/metronome/types/customers/plan_end_params.py @@ -14,6 +14,8 @@ 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. diff --git a/src/metronome/types/customers/plan_end_response.py b/src/metronome/types/customers/plan_end_response.py index f4119d4b..0937a4c9 100644 --- a/src/metronome/types/customers/plan_end_response.py +++ b/src/metronome/types/customers/plan_end_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ..._models import BaseModel __all__ = ["PlanEndResponse"] diff --git a/src/metronome/types/customers/plan_list_params.py b/src/metronome/types/customers/plan_list_params.py index 91c204f8..5d266c5c 100644 --- a/src/metronome/types/customers/plan_list_params.py +++ b/src/metronome/types/customers/plan_list_params.py @@ -2,12 +2,14 @@ from __future__ import annotations -from typing_extensions import TypedDict +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""" diff --git a/src/metronome/types/customers/plan_list_price_adjustments_params.py b/src/metronome/types/customers/plan_list_price_adjustments_params.py index cd59b6eb..24d42226 100644 --- a/src/metronome/types/customers/plan_list_price_adjustments_params.py +++ b/src/metronome/types/customers/plan_list_price_adjustments_params.py @@ -10,6 +10,8 @@ class PlanListPriceAdjustmentsParams(TypedDict, total=False): customer_id: Required[str] + customer_plan_id: Required[str] + limit: int """Max number of results that should be returned""" diff --git a/src/metronome/types/customers/plan_list_response.py b/src/metronome/types/customers/plan_list_response.py index 8ff2c3ff..1c9f6d9d 100644 --- a/src/metronome/types/customers/plan_list_response.py +++ b/src/metronome/types/customers/plan_list_response.py @@ -4,7 +4,7 @@ from datetime import datetime from ..._models import BaseModel -from ..shared.credit_type import CreditType +from ..shared.credit_type_data import CreditTypeData __all__ = ["PlanListResponse", "TrialInfo", "TrialInfoSpendingCap"] @@ -14,7 +14,7 @@ class TrialInfoSpendingCap(BaseModel): amount_remaining: float - credit_type: CreditType + credit_type: CreditTypeData class TrialInfo(BaseModel): diff --git a/src/metronome/types/plan_detail.py b/src/metronome/types/plan_detail.py index bd28ed06..b6b4bc63 100644 --- a/src/metronome/types/plan_detail.py +++ b/src/metronome/types/plan_detail.py @@ -3,7 +3,7 @@ from typing import Dict, List, Optional from .._models import BaseModel -from .shared.credit_type import CreditType +from .shared.credit_type_data import CreditTypeData __all__ = ["PlanDetail", "CreditGrant", "Minimum", "OverageRate"] @@ -11,11 +11,11 @@ class CreditGrant(BaseModel): amount_granted: float - amount_granted_credit_type: CreditType + amount_granted_credit_type: CreditTypeData amount_paid: float - amount_paid_credit_type: CreditType + amount_paid_credit_type: CreditTypeData effective_duration: float @@ -33,7 +33,7 @@ class CreditGrant(BaseModel): class Minimum(BaseModel): - credit_type: CreditType + credit_type: CreditTypeData name: str @@ -47,9 +47,9 @@ class Minimum(BaseModel): class OverageRate(BaseModel): - credit_type: CreditType + credit_type: CreditTypeData - fiat_credit_type: CreditType + fiat_credit_type: CreditTypeData start_period: float """Used in price ramps. diff --git a/src/metronome/types/plan_get_details_response.py b/src/metronome/types/plan_get_details_response.py index c8f170ae..de9fe820 100644 --- a/src/metronome/types/plan_get_details_response.py +++ b/src/metronome/types/plan_get_details_response.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from .._models import BaseModel from .plan_detail import PlanDetail diff --git a/src/metronome/types/plan_list_charges_params.py b/src/metronome/types/plan_list_charges_params.py index 45463cb6..08b4eead 100644 --- a/src/metronome/types/plan_list_charges_params.py +++ b/src/metronome/types/plan_list_charges_params.py @@ -2,12 +2,14 @@ from __future__ import annotations -from typing_extensions import TypedDict +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""" diff --git a/src/metronome/types/plan_list_charges_response.py b/src/metronome/types/plan_list_charges_response.py index 040360d1..6fd57d67 100644 --- a/src/metronome/types/plan_list_charges_response.py +++ b/src/metronome/types/plan_list_charges_response.py @@ -4,7 +4,7 @@ from typing_extensions import Literal from .._models import BaseModel -from .shared.credit_type import CreditType +from .shared.credit_type_data import CreditTypeData __all__ = ["PlanListChargesResponse", "Price", "UnitConversion"] @@ -38,7 +38,7 @@ class PlanListChargesResponse(BaseModel): charge_type: Literal["usage", "fixed", "composite", "minimum", "seat"] - credit_type: CreditType + credit_type: CreditTypeData custom_fields: Dict[str, str] diff --git a/src/metronome/types/plan_list_customers_params.py b/src/metronome/types/plan_list_customers_params.py index 330001e8..0acc7a27 100644 --- a/src/metronome/types/plan_list_customers_params.py +++ b/src/metronome/types/plan_list_customers_params.py @@ -2,12 +2,14 @@ from __future__ import annotations -from typing_extensions import Literal, TypedDict +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""" diff --git a/src/metronome/types/shared/__init__.py b/src/metronome/types/shared/__init__.py index e5ed8312..0ff9f345 100644 --- a/src/metronome/types/shared/__init__.py +++ b/src/metronome/types/shared/__init__.py @@ -7,9 +7,9 @@ from .credit import Credit as Credit from .discount import Discount as Discount from .override import Override as Override -from .credit_type import CreditType as CreditType from .pro_service import ProService as ProService from .property_filter import PropertyFilter as PropertyFilter +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 diff --git a/src/metronome/types/shared/commit.py b/src/metronome/types/shared/commit.py index dedf4572..44a23b34 100644 --- a/src/metronome/types/shared/commit.py +++ b/src/metronome/types/shared/commit.py @@ -228,6 +228,19 @@ class Commit(BaseModel): 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 @@ -257,9 +270,19 @@ class Commit(BaseModel): will apply first. """ + rate_type: Optional[Literal["COMMIT_RATE", "LIST_RATE"]] = None + 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.""" + + 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/contract_without_amendments.py b/src/metronome/types/shared/contract_without_amendments.py index 5bad6fd2..e4254ace 100644 --- a/src/metronome/types/shared/contract_without_amendments.py +++ b/src/metronome/types/shared/contract_without_amendments.py @@ -32,7 +32,10 @@ class Transition(BaseModel): class UsageStatementSchedule(BaseModel): - frequency: Literal["MONTHLY", "QUARTERLY"] + billing_anchor_date: datetime + """Contract usage statements follow a selected cadence based on this date.""" + + frequency: Literal["MONTHLY", "QUARTERLY", "ANNUAL"] class ResellerRoyalty(BaseModel): @@ -121,6 +124,15 @@ class ContractWithoutAmendments(BaseModel): 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. + """ + total_contract_value: Optional[float] = None """This field's availability is dependent on your client's configuration.""" diff --git a/src/metronome/types/shared/credit.py b/src/metronome/types/shared/credit.py index 59d89644..4e49c2ba 100755 --- a/src/metronome/types/shared/credit.py +++ b/src/metronome/types/shared/credit.py @@ -123,6 +123,19 @@ class Credit(BaseModel): 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 @@ -146,5 +159,15 @@ class Credit(BaseModel): will apply first. """ + rate_type: Optional[Literal["COMMIT_RATE", "LIST_RATE"]] = None + salesforce_opportunity_id: Optional[str] = None """This field's availability is dependent on your client's configuration.""" + + 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.py b/src/metronome/types/shared/credit_type_data.py similarity index 70% rename from src/metronome/types/shared/credit_type.py rename to src/metronome/types/shared/credit_type_data.py index 37865ca1..288c9d7e 100644 --- a/src/metronome/types/shared/credit_type.py +++ b/src/metronome/types/shared/credit_type_data.py @@ -1,13 +1,12 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ..._models import BaseModel -__all__ = ["CreditType"] +__all__ = ["CreditTypeData"] -class CreditType(BaseModel): +class CreditTypeData(BaseModel): id: str name: str diff --git a/src/metronome/types/shared/discount.py b/src/metronome/types/shared/discount.py index 12d9a04a..5ddd5492 100644 --- a/src/metronome/types/shared/discount.py +++ b/src/metronome/types/shared/discount.py @@ -1,6 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -from typing import Optional +from typing import Dict, Optional from ..._models import BaseModel from .schedule_point_in_time import SchedulePointInTime @@ -21,6 +21,8 @@ class Discount(BaseModel): schedule: SchedulePointInTime + custom_fields: Optional[Dict[str, str]] = None + name: Optional[str] = None netsuite_sales_order_id: Optional[str] = None diff --git a/src/metronome/types/shared/id.py b/src/metronome/types/shared/id.py index c71e52a3..72ecbffa 100644 --- a/src/metronome/types/shared/id.py +++ b/src/metronome/types/shared/id.py @@ -1,7 +1,6 @@ # File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - from ..._models import BaseModel __all__ = ["ID"] diff --git a/src/metronome/types/shared/override.py b/src/metronome/types/shared/override.py index 1e9dfc85..ab3bc73d 100644 --- a/src/metronome/types/shared/override.py +++ b/src/metronome/types/shared/override.py @@ -6,12 +6,14 @@ from .tier import Tier from ..._models import BaseModel -from .credit_type import CreditType +from .credit_type_data import CreditTypeData __all__ = ["Override", "OverrideSpecifier", "OverrideTier", "OverwriteRate", "Product"] class OverrideSpecifier(BaseModel): + commit_ids: Optional[List[str]] = None + presentation_group_values: Optional[Dict[str, Optional[str]]] = None pricing_group_values: Optional[Dict[str, str]] = None @@ -30,7 +32,7 @@ class OverrideTier(BaseModel): class OverwriteRate(BaseModel): rate_type: Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "TIERED", "CUSTOM"] - credit_type: Optional[CreditType] = None + credit_type: Optional[CreditTypeData] = None custom_rate: Optional[Dict[str, object]] = None """Only set for CUSTOM rate_type. @@ -39,7 +41,10 @@ class OverwriteRate(BaseModel): """ is_prorated: Optional[bool] = None - """Default proration configuration. Only valid for SUBSCRIPTION rate_type.""" + """Default proration configuration. + + Only valid for SUBSCRIPTION rate_type. Must be set to true. + """ price: Optional[float] = None """Default price. @@ -68,14 +73,19 @@ class Override(BaseModel): applicable_product_tags: Optional[List[str]] = None - credit_type: Optional[CreditType] = 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.""" + """Default proration configuration. + + Only valid for SUBSCRIPTION rate_type. Must be set to true. + """ multiplier: Optional[float] = None @@ -101,6 +111,8 @@ class Override(BaseModel): rate_type: Optional[Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "TIERED", "CUSTOM"]] = None + target: Optional[Literal["COMMIT_RATE", "LIST_RATE"]] = None + tiers: Optional[List[Tier]] = None """Only set for TIERED rate_type.""" diff --git a/src/metronome/types/shared/rate.py b/src/metronome/types/shared/rate.py index d49a4832..e464d227 100644 --- a/src/metronome/types/shared/rate.py +++ b/src/metronome/types/shared/rate.py @@ -5,7 +5,7 @@ from .tier import Tier from ..._models import BaseModel -from .credit_type import CreditType +from .credit_type_data import CreditTypeData __all__ = ["Rate"] @@ -13,7 +13,7 @@ class Rate(BaseModel): rate_type: Literal["FLAT", "PERCENTAGE", "SUBSCRIPTION", "CUSTOM", "TIERED"] - credit_type: Optional[CreditType] = None + credit_type: Optional[CreditTypeData] = None custom_rate: Optional[Dict[str, object]] = None """Only set for CUSTOM rate_type. @@ -22,7 +22,10 @@ class Rate(BaseModel): """ is_prorated: Optional[bool] = None - """Default proration configuration. Only valid for SUBSCRIPTION rate_type.""" + """Default proration configuration. + + Only valid for SUBSCRIPTION rate_type. Must be set to true. + """ price: Optional[float] = None """Default price. diff --git a/src/metronome/types/shared/schedule_duration.py b/src/metronome/types/shared/schedule_duration.py index 5c0c2c78..5e79ee48 100755 --- a/src/metronome/types/shared/schedule_duration.py +++ b/src/metronome/types/shared/schedule_duration.py @@ -4,7 +4,7 @@ from datetime import datetime from ..._models import BaseModel -from .credit_type import CreditType +from .credit_type_data import CreditTypeData __all__ = ["ScheduleDuration", "ScheduleItem"] @@ -22,4 +22,4 @@ class ScheduleItem(BaseModel): class ScheduleDuration(BaseModel): schedule_items: List[ScheduleItem] - credit_type: Optional[CreditType] = None + 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 index 7f192244..b4cdb48c 100644 --- a/src/metronome/types/shared/schedule_point_in_time.py +++ b/src/metronome/types/shared/schedule_point_in_time.py @@ -4,7 +4,7 @@ from datetime import datetime from ..._models import BaseModel -from .credit_type import CreditType +from .credit_type_data import CreditTypeData __all__ = ["SchedulePointInTime", "ScheduleItem"] @@ -24,6 +24,6 @@ class ScheduleItem(BaseModel): class SchedulePointInTime(BaseModel): - credit_type: Optional[CreditType] = None + credit_type: Optional[CreditTypeData] = None schedule_items: Optional[List[ScheduleItem]] = None diff --git a/tests/api_resources/contracts/rate_cards/test_rates.py b/tests/api_resources/contracts/rate_cards/test_rates.py index 29268877..739f1328 100644 --- a/tests/api_resources/contracts/rate_cards/test_rates.py +++ b/tests/api_resources/contracts/rate_cards/test_rates.py @@ -46,7 +46,7 @@ def test_method_list_with_all_params(self, client: Metronome) -> None: }, "pricing_group_values": {"foo": "string"}, "product_id": "d6300dbb-882e-4d2d-8dec-5125d16b65d0", - "product_tags": ["string", "string", "string"], + "product_tags": ["string"], } ], ) @@ -97,6 +97,16 @@ def test_method_add_with_all_params(self, client: Metronome) -> None: rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", rate_type="FLAT", starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), + 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"), @@ -108,15 +118,7 @@ def test_method_add_with_all_params(self, client: Metronome) -> None: { "price": 0, "size": 0, - }, - { - "price": 0, - "size": 0, - }, - { - "price": 0, - "size": 0, - }, + } ], use_list_prices=True, ) @@ -156,11 +158,6 @@ def test_streaming_response_add(self, client: Metronome) -> None: @parametrize def test_method_add_many(self, client: Metronome) -> None: - rate = client.contracts.rate_cards.rates.add_many() - assert_matches_type(RateAddManyResponse, rate, path=["response"]) - - @parametrize - def test_method_add_many_with_all_params(self, client: Metronome) -> None: rate = client.contracts.rate_cards.rates.add_many( rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", rates=[ @@ -169,62 +166,12 @@ def test_method_add_many_with_all_params(self, client: Metronome) -> None: "product_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", "rate_type": "FLAT", "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - "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": { - "region": "us-west-2", - "cloud": "aws", - }, - "quantity": 0, - "tiers": [ - { - "price": 0, - "size": 0, - }, - { - "price": 0, - "size": 0, - }, - { - "price": 0, - "size": 0, - }, - ], - "use_list_prices": True, }, { "entitled": True, "product_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", "rate_type": "FLAT", "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - "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": 120, - "pricing_group_values": { - "region": "us-east-2", - "cloud": "aws", - }, - "quantity": 0, - "tiers": [ - { - "price": 0, - "size": 0, - }, - { - "price": 0, - "size": 0, - }, - { - "price": 0, - "size": 0, - }, - ], - "use_list_prices": True, }, ], ) @@ -232,7 +179,23 @@ def test_method_add_many_with_all_params(self, client: Metronome) -> None: @parametrize def test_raw_response_add_many(self, client: Metronome) -> None: - response = client.contracts.rate_cards.rates.with_raw_response.add_many() + response = client.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" @@ -241,7 +204,23 @@ def test_raw_response_add_many(self, client: Metronome) -> None: @parametrize def test_streaming_response_add_many(self, client: Metronome) -> None: - with client.contracts.rate_cards.rates.with_streaming_response.add_many() as response: + with client.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" @@ -277,7 +256,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncMetronome) - }, "pricing_group_values": {"foo": "string"}, "product_id": "d6300dbb-882e-4d2d-8dec-5125d16b65d0", - "product_tags": ["string", "string", "string"], + "product_tags": ["string"], } ], ) @@ -328,6 +307,16 @@ async def test_method_add_with_all_params(self, async_client: AsyncMetronome) -> rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", rate_type="FLAT", starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), + 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"), @@ -339,15 +328,7 @@ async def test_method_add_with_all_params(self, async_client: AsyncMetronome) -> { "price": 0, "size": 0, - }, - { - "price": 0, - "size": 0, - }, - { - "price": 0, - "size": 0, - }, + } ], use_list_prices=True, ) @@ -387,11 +368,6 @@ async def test_streaming_response_add(self, async_client: AsyncMetronome) -> Non @parametrize async def test_method_add_many(self, async_client: AsyncMetronome) -> None: - rate = await async_client.contracts.rate_cards.rates.add_many() - assert_matches_type(RateAddManyResponse, rate, path=["response"]) - - @parametrize - async def test_method_add_many_with_all_params(self, async_client: AsyncMetronome) -> None: rate = await async_client.contracts.rate_cards.rates.add_many( rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", rates=[ @@ -400,62 +376,12 @@ async def test_method_add_many_with_all_params(self, async_client: AsyncMetronom "product_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", "rate_type": "FLAT", "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - "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": { - "region": "us-west-2", - "cloud": "aws", - }, - "quantity": 0, - "tiers": [ - { - "price": 0, - "size": 0, - }, - { - "price": 0, - "size": 0, - }, - { - "price": 0, - "size": 0, - }, - ], - "use_list_prices": True, }, { "entitled": True, "product_id": "13117714-3f05-48e5-a6e9-a66093f13b4d", "rate_type": "FLAT", "starting_at": parse_datetime("2020-01-01T00:00:00.000Z"), - "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": 120, - "pricing_group_values": { - "region": "us-east-2", - "cloud": "aws", - }, - "quantity": 0, - "tiers": [ - { - "price": 0, - "size": 0, - }, - { - "price": 0, - "size": 0, - }, - { - "price": 0, - "size": 0, - }, - ], - "use_list_prices": True, }, ], ) @@ -463,7 +389,23 @@ async def test_method_add_many_with_all_params(self, async_client: AsyncMetronom @parametrize async def test_raw_response_add_many(self, async_client: AsyncMetronome) -> None: - response = await async_client.contracts.rate_cards.rates.with_raw_response.add_many() + response = await async_client.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" @@ -472,7 +414,23 @@ async def test_raw_response_add_many(self, async_client: AsyncMetronome) -> None @parametrize async def test_streaming_response_add_many(self, async_client: AsyncMetronome) -> None: - async with async_client.contracts.rate_cards.rates.with_streaming_response.add_many() as response: + async with async_client.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" diff --git a/tests/api_resources/contracts/test_products.py b/tests/api_resources/contracts/test_products.py index 565baaaa..16c7d515 100644 --- a/tests/api_resources/contracts/test_products.py +++ b/tests/api_resources/contracts/test_products.py @@ -39,18 +39,14 @@ def test_method_create_with_all_params(self, client: Metronome) -> None: name="My Product", type="FIXED", billable_metric_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - composite_product_ids=[ - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - composite_tags=["string", "string", "string"], + composite_product_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + composite_tags=["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", "string", "string"], - pricing_group_key=["string", "string", "string"], + presentation_group_key=["string"], + pricing_group_key=["string"], quantity_conversion={ "conversion_factor": 0, "operation": "MULTIPLY", @@ -60,7 +56,7 @@ def test_method_create_with_all_params(self, client: Metronome) -> None: "decimal_places": 0, "rounding_method": "ROUND_UP", }, - tags=["string", "string", "string"], + tags=["string"], ) assert_matches_type(ProductCreateResponse, product, path=["response"]) @@ -135,19 +131,15 @@ def test_method_update_with_all_params(self, client: Metronome) -> None: 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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - composite_tags=["string", "string", "string"], + 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", "string", "string"], - pricing_group_key=["string", "string", "string"], + presentation_group_key=["string"], + pricing_group_key=["string"], quantity_conversion={ "conversion_factor": 0, "operation": "MULTIPLY", @@ -157,7 +149,7 @@ def test_method_update_with_all_params(self, client: Metronome) -> None: "decimal_places": 0, "rounding_method": "ROUND_UP", }, - tags=["string", "string", "string"], + tags=["string"], ) assert_matches_type(ProductUpdateResponse, product, path=["response"]) @@ -270,18 +262,14 @@ async def test_method_create_with_all_params(self, async_client: AsyncMetronome) name="My Product", type="FIXED", billable_metric_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - composite_product_ids=[ - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - composite_tags=["string", "string", "string"], + composite_product_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + composite_tags=["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", "string", "string"], - pricing_group_key=["string", "string", "string"], + presentation_group_key=["string"], + pricing_group_key=["string"], quantity_conversion={ "conversion_factor": 0, "operation": "MULTIPLY", @@ -291,7 +279,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncMetronome) "decimal_places": 0, "rounding_method": "ROUND_UP", }, - tags=["string", "string", "string"], + tags=["string"], ) assert_matches_type(ProductCreateResponse, product, path=["response"]) @@ -366,19 +354,15 @@ async def test_method_update_with_all_params(self, async_client: AsyncMetronome) 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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - composite_tags=["string", "string", "string"], + 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", "string", "string"], - pricing_group_key=["string", "string", "string"], + presentation_group_key=["string"], + pricing_group_key=["string"], quantity_conversion={ "conversion_factor": 0, "operation": "MULTIPLY", @@ -388,7 +372,7 @@ async def test_method_update_with_all_params(self, async_client: AsyncMetronome) "decimal_places": 0, "rounding_method": "ROUND_UP", }, - tags=["string", "string", "string"], + tags=["string"], ) assert_matches_type(ProductUpdateResponse, product, path=["response"]) diff --git a/tests/api_resources/contracts/test_rate_cards.py b/tests/api_resources/contracts/test_rate_cards.py index 16c97d8e..909e1d1e 100644 --- a/tests/api_resources/contracts/test_rate_cards.py +++ b/tests/api_resources/contracts/test_rate_cards.py @@ -126,19 +126,8 @@ def test_method_update_with_all_params(self, client: Metronome) -> None: "name": "name", "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "name": "name", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "name": "name", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, + } ], - custom_fields={"foo": "string"}, description="My Updated Rate Card Description", name="My Updated Rate Card", ) @@ -368,19 +357,8 @@ async def test_method_update_with_all_params(self, async_client: AsyncMetronome) "name": "name", "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "name": "name", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "name": "name", - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, + } ], - custom_fields={"foo": "string"}, description="My Updated Rate Card Description", name="My Updated Rate Card", ) diff --git a/tests/api_resources/customers/test_billing_config.py b/tests/api_resources/customers/test_billing_config.py index 5e0ffea4..2378234a 100644 --- a/tests/api_resources/customers/test_billing_config.py +++ b/tests/api_resources/customers/test_billing_config.py @@ -20,8 +20,8 @@ class TestBillingConfig: @parametrize def test_method_create(self, client: Metronome) -> None: billing_config = client.customers.billing_config.create( - billing_provider_type="aws_marketplace", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + billing_provider_type="aws_marketplace", billing_provider_customer_id="cus_AJ6y20bjkOOayM", ) assert billing_config is None @@ -29,8 +29,8 @@ def test_method_create(self, client: Metronome) -> None: @parametrize def test_method_create_with_all_params(self, client: Metronome) -> None: billing_config = client.customers.billing_config.create( - billing_provider_type="aws_marketplace", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + billing_provider_type="aws_marketplace", billing_provider_customer_id="cus_AJ6y20bjkOOayM", aws_product_code="aws_product_code", aws_region="af-south-1", @@ -41,8 +41,8 @@ def test_method_create_with_all_params(self, client: Metronome) -> None: @parametrize def test_raw_response_create(self, client: Metronome) -> None: response = client.customers.billing_config.with_raw_response.create( - billing_provider_type="aws_marketplace", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + billing_provider_type="aws_marketplace", billing_provider_customer_id="cus_AJ6y20bjkOOayM", ) @@ -54,8 +54,8 @@ def test_raw_response_create(self, client: Metronome) -> None: @parametrize def test_streaming_response_create(self, client: Metronome) -> None: with client.customers.billing_config.with_streaming_response.create( - billing_provider_type="aws_marketplace", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + billing_provider_type="aws_marketplace", billing_provider_customer_id="cus_AJ6y20bjkOOayM", ) as response: assert not response.is_closed @@ -70,24 +70,24 @@ def test_streaming_response_create(self, client: Metronome) -> None: 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.customers.billing_config.with_raw_response.create( - billing_provider_type="aws_marketplace", customer_id="", + billing_provider_type="aws_marketplace", billing_provider_customer_id="cus_AJ6y20bjkOOayM", ) @parametrize def test_method_retrieve(self, client: Metronome) -> None: billing_config = client.customers.billing_config.retrieve( - billing_provider_type="aws_marketplace", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + billing_provider_type="aws_marketplace", ) assert_matches_type(BillingConfigRetrieveResponse, billing_config, path=["response"]) @parametrize def test_raw_response_retrieve(self, client: Metronome) -> None: response = client.customers.billing_config.with_raw_response.retrieve( - billing_provider_type="aws_marketplace", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + billing_provider_type="aws_marketplace", ) assert response.is_closed is True @@ -98,8 +98,8 @@ def test_raw_response_retrieve(self, client: Metronome) -> None: @parametrize def test_streaming_response_retrieve(self, client: Metronome) -> None: with client.customers.billing_config.with_streaming_response.retrieve( - billing_provider_type="aws_marketplace", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + billing_provider_type="aws_marketplace", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -113,23 +113,23 @@ def test_streaming_response_retrieve(self, client: Metronome) -> None: 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.customers.billing_config.with_raw_response.retrieve( - billing_provider_type="aws_marketplace", customer_id="", + billing_provider_type="aws_marketplace", ) @parametrize def test_method_delete(self, client: Metronome) -> None: billing_config = client.customers.billing_config.delete( - billing_provider_type="aws_marketplace", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + billing_provider_type="aws_marketplace", ) assert billing_config is None @parametrize def test_raw_response_delete(self, client: Metronome) -> None: response = client.customers.billing_config.with_raw_response.delete( - billing_provider_type="aws_marketplace", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + billing_provider_type="aws_marketplace", ) assert response.is_closed is True @@ -140,8 +140,8 @@ def test_raw_response_delete(self, client: Metronome) -> None: @parametrize def test_streaming_response_delete(self, client: Metronome) -> None: with client.customers.billing_config.with_streaming_response.delete( - billing_provider_type="aws_marketplace", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + billing_provider_type="aws_marketplace", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -155,8 +155,8 @@ def test_streaming_response_delete(self, client: Metronome) -> None: 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.customers.billing_config.with_raw_response.delete( - billing_provider_type="aws_marketplace", customer_id="", + billing_provider_type="aws_marketplace", ) @@ -166,8 +166,8 @@ class TestAsyncBillingConfig: @parametrize async def test_method_create(self, async_client: AsyncMetronome) -> None: billing_config = await async_client.customers.billing_config.create( - billing_provider_type="aws_marketplace", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + billing_provider_type="aws_marketplace", billing_provider_customer_id="cus_AJ6y20bjkOOayM", ) assert billing_config is None @@ -175,8 +175,8 @@ async def test_method_create(self, async_client: AsyncMetronome) -> None: @parametrize async def test_method_create_with_all_params(self, async_client: AsyncMetronome) -> None: billing_config = await async_client.customers.billing_config.create( - billing_provider_type="aws_marketplace", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + billing_provider_type="aws_marketplace", billing_provider_customer_id="cus_AJ6y20bjkOOayM", aws_product_code="aws_product_code", aws_region="af-south-1", @@ -187,8 +187,8 @@ async def test_method_create_with_all_params(self, async_client: AsyncMetronome) @parametrize async def test_raw_response_create(self, async_client: AsyncMetronome) -> None: response = await async_client.customers.billing_config.with_raw_response.create( - billing_provider_type="aws_marketplace", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + billing_provider_type="aws_marketplace", billing_provider_customer_id="cus_AJ6y20bjkOOayM", ) @@ -200,8 +200,8 @@ async def test_raw_response_create(self, async_client: AsyncMetronome) -> None: @parametrize async def test_streaming_response_create(self, async_client: AsyncMetronome) -> None: async with async_client.customers.billing_config.with_streaming_response.create( - billing_provider_type="aws_marketplace", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + billing_provider_type="aws_marketplace", billing_provider_customer_id="cus_AJ6y20bjkOOayM", ) as response: assert not response.is_closed @@ -216,24 +216,24 @@ async def test_streaming_response_create(self, async_client: AsyncMetronome) -> 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.customers.billing_config.with_raw_response.create( - billing_provider_type="aws_marketplace", customer_id="", + billing_provider_type="aws_marketplace", billing_provider_customer_id="cus_AJ6y20bjkOOayM", ) @parametrize async def test_method_retrieve(self, async_client: AsyncMetronome) -> None: billing_config = await async_client.customers.billing_config.retrieve( - billing_provider_type="aws_marketplace", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + billing_provider_type="aws_marketplace", ) assert_matches_type(BillingConfigRetrieveResponse, billing_config, path=["response"]) @parametrize async def test_raw_response_retrieve(self, async_client: AsyncMetronome) -> None: response = await async_client.customers.billing_config.with_raw_response.retrieve( - billing_provider_type="aws_marketplace", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + billing_provider_type="aws_marketplace", ) assert response.is_closed is True @@ -244,8 +244,8 @@ async def test_raw_response_retrieve(self, async_client: AsyncMetronome) -> None @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncMetronome) -> None: async with async_client.customers.billing_config.with_streaming_response.retrieve( - billing_provider_type="aws_marketplace", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + billing_provider_type="aws_marketplace", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -259,23 +259,23 @@ async def test_streaming_response_retrieve(self, async_client: AsyncMetronome) - 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.customers.billing_config.with_raw_response.retrieve( - billing_provider_type="aws_marketplace", customer_id="", + billing_provider_type="aws_marketplace", ) @parametrize async def test_method_delete(self, async_client: AsyncMetronome) -> None: billing_config = await async_client.customers.billing_config.delete( - billing_provider_type="aws_marketplace", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + billing_provider_type="aws_marketplace", ) assert billing_config is None @parametrize async def test_raw_response_delete(self, async_client: AsyncMetronome) -> None: response = await async_client.customers.billing_config.with_raw_response.delete( - billing_provider_type="aws_marketplace", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + billing_provider_type="aws_marketplace", ) assert response.is_closed is True @@ -286,8 +286,8 @@ async def test_raw_response_delete(self, async_client: AsyncMetronome) -> None: @parametrize async def test_streaming_response_delete(self, async_client: AsyncMetronome) -> None: async with async_client.customers.billing_config.with_streaming_response.delete( - billing_provider_type="aws_marketplace", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + billing_provider_type="aws_marketplace", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -301,6 +301,6 @@ async def test_streaming_response_delete(self, async_client: AsyncMetronome) -> 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.customers.billing_config.with_raw_response.delete( - billing_provider_type="aws_marketplace", customer_id="", + billing_provider_type="aws_marketplace", ) diff --git a/tests/api_resources/customers/test_commits.py b/tests/api_resources/customers/test_commits.py index 7989444d..21311567 100644 --- a/tests/api_resources/customers/test_commits.py +++ b/tests/api_resources/customers/test_commits.py @@ -58,13 +58,9 @@ def test_method_create_with_all_params(self, client: Metronome) -> None: priority=100, product_id="f14d6729-6a44-4b13-9908-9387f1918790", type="PREPAID", - applicable_contract_ids=["string", "string", "string"], - applicable_product_ids=[ - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - applicable_product_tags=["string", "string", "string"], + 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="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", @@ -82,7 +78,7 @@ def test_method_create_with_all_params(self, client: Metronome) -> None: "schedule_items": [ { "timestamp": parse_datetime("2020-03-01T00:00:00.000Z"), - "amount": 10000000, + "amount": 0, "quantity": 1, "unit_price": 10000000, } @@ -90,7 +86,9 @@ def test_method_create_with_all_params(self, client: Metronome) -> None: }, name="My Commit", netsuite_sales_order_id="netsuite_sales_order_id", + rate_type="COMMIT_RATE", salesforce_opportunity_id="salesforce_opportunity_id", + uniqueness_key="x", ) assert_matches_type(CommitCreateResponse, commit, path=["response"]) @@ -157,6 +155,7 @@ def test_method_list_with_all_params(self, client: Metronome) -> None: 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, next_page="next_page", @@ -272,13 +271,9 @@ async def test_method_create_with_all_params(self, async_client: AsyncMetronome) priority=100, product_id="f14d6729-6a44-4b13-9908-9387f1918790", type="PREPAID", - applicable_contract_ids=["string", "string", "string"], - applicable_product_ids=[ - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - applicable_product_tags=["string", "string", "string"], + 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="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", @@ -296,7 +291,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncMetronome) "schedule_items": [ { "timestamp": parse_datetime("2020-03-01T00:00:00.000Z"), - "amount": 10000000, + "amount": 0, "quantity": 1, "unit_price": 10000000, } @@ -304,7 +299,9 @@ async def test_method_create_with_all_params(self, async_client: AsyncMetronome) }, name="My Commit", netsuite_sales_order_id="netsuite_sales_order_id", + rate_type="COMMIT_RATE", salesforce_opportunity_id="salesforce_opportunity_id", + uniqueness_key="x", ) assert_matches_type(CommitCreateResponse, commit, path=["response"]) @@ -371,6 +368,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncMetronome) - 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, next_page="next_page", diff --git a/tests/api_resources/customers/test_credits.py b/tests/api_resources/customers/test_credits.py index 3e95385c..b5e9da41 100644 --- a/tests/api_resources/customers/test_credits.py +++ b/tests/api_resources/customers/test_credits.py @@ -56,18 +56,16 @@ def test_method_create_with_all_params(self, client: Metronome) -> None: customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", priority=100, product_id="f14d6729-6a44-4b13-9908-9387f1918790", - applicable_contract_ids=["string", "string", "string"], - applicable_product_ids=[ - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - applicable_product_tags=["string", "string", "string"], + 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", + uniqueness_key="x", ) assert_matches_type(CreditCreateResponse, credit, path=["response"]) @@ -132,6 +130,7 @@ def test_method_list_with_all_params(self, client: Metronome) -> None: 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, next_page="next_page", @@ -238,18 +237,16 @@ async def test_method_create_with_all_params(self, async_client: AsyncMetronome) customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", priority=100, product_id="f14d6729-6a44-4b13-9908-9387f1918790", - applicable_contract_ids=["string", "string", "string"], - applicable_product_ids=[ - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - applicable_product_tags=["string", "string", "string"], + 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", + uniqueness_key="x", ) assert_matches_type(CreditCreateResponse, credit, path=["response"]) @@ -314,6 +311,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncMetronome) - 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, next_page="next_page", diff --git a/tests/api_resources/customers/test_invoices.py b/tests/api_resources/customers/test_invoices.py index 28256237..44a0eca6 100644 --- a/tests/api_resources/customers/test_invoices.py +++ b/tests/api_resources/customers/test_invoices.py @@ -27,16 +27,16 @@ class TestInvoices: @parametrize def test_method_retrieve(self, client: Metronome) -> None: invoice = client.customers.invoices.retrieve( - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", 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.customers.invoices.retrieve( - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", 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"]) @@ -44,8 +44,8 @@ def test_method_retrieve_with_all_params(self, client: Metronome) -> None: @parametrize def test_raw_response_retrieve(self, client: Metronome) -> None: response = client.customers.invoices.with_raw_response.retrieve( - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", ) assert response.is_closed is True @@ -56,8 +56,8 @@ def test_raw_response_retrieve(self, client: Metronome) -> None: @parametrize def test_streaming_response_retrieve(self, client: Metronome) -> None: with client.customers.invoices.with_streaming_response.retrieve( - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", 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" @@ -71,14 +71,14 @@ def test_streaming_response_retrieve(self, client: Metronome) -> None: 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.customers.invoices.with_raw_response.retrieve( - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", 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.customers.invoices.with_raw_response.retrieve( - invoice_id="", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + invoice_id="", ) @parametrize @@ -265,16 +265,16 @@ class TestAsyncInvoices: @parametrize async def test_method_retrieve(self, async_client: AsyncMetronome) -> None: invoice = await async_client.customers.invoices.retrieve( - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", 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.customers.invoices.retrieve( - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", 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"]) @@ -282,8 +282,8 @@ async def test_method_retrieve_with_all_params(self, async_client: AsyncMetronom @parametrize async def test_raw_response_retrieve(self, async_client: AsyncMetronome) -> None: response = await async_client.customers.invoices.with_raw_response.retrieve( - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", ) assert response.is_closed is True @@ -294,8 +294,8 @@ async def test_raw_response_retrieve(self, async_client: AsyncMetronome) -> None @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncMetronome) -> None: async with async_client.customers.invoices.with_streaming_response.retrieve( - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", 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" @@ -309,14 +309,14 @@ async def test_streaming_response_retrieve(self, async_client: AsyncMetronome) - 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.customers.invoices.with_raw_response.retrieve( - invoice_id="6a37bb88-8538-48c5-b37b-a41c836328bd", 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.customers.invoices.with_raw_response.retrieve( - invoice_id="", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + invoice_id="", ) @parametrize diff --git a/tests/api_resources/customers/test_plans.py b/tests/api_resources/customers/test_plans.py index ae3a2f32..f1bc3405 100644 --- a/tests/api_resources/customers/test_plans.py +++ b/tests/api_resources/customers/test_plans.py @@ -93,17 +93,7 @@ def test_method_add_with_all_params(self, client: Metronome) -> None: "custom_credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "fiat_currency_credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "to_fiat_conversion_factor": 0, - }, - { - "custom_credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "fiat_currency_credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "to_fiat_conversion_factor": 0, - }, - { - "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=[ { @@ -113,23 +103,7 @@ def test_method_add_with_all_params(self, client: Metronome) -> None: "quantity": 0, "tier": 0, "value": 0, - }, - { - "adjustment_type": "percentage", - "charge_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "start_period": 0, - "quantity": 0, - "tier": 0, - "value": 0, - }, - { - "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, @@ -181,16 +155,16 @@ def test_path_params_add(self, client: Metronome) -> None: @parametrize def test_method_end(self, client: Metronome) -> None: plan = client.customers.plans.end( - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", 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.customers.plans.end( - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", 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, @@ -200,8 +174,8 @@ def test_method_end_with_all_params(self, client: Metronome) -> None: @parametrize def test_raw_response_end(self, client: Metronome) -> None: response = client.customers.plans.with_raw_response.end( - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", ) assert response.is_closed is True @@ -212,8 +186,8 @@ def test_raw_response_end(self, client: Metronome) -> None: @parametrize def test_streaming_response_end(self, client: Metronome) -> None: with client.customers.plans.with_streaming_response.end( - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", 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" @@ -227,29 +201,29 @@ def test_streaming_response_end(self, client: Metronome) -> None: 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.customers.plans.with_raw_response.end( - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", 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.customers.plans.with_raw_response.end( - customer_plan_id="", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + customer_plan_id="", ) @parametrize def test_method_list_price_adjustments(self, client: Metronome) -> None: plan = client.customers.plans.list_price_adjustments( - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", 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.customers.plans.list_price_adjustments( - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", limit=1, next_page="next_page", ) @@ -258,8 +232,8 @@ def test_method_list_price_adjustments_with_all_params(self, client: Metronome) @parametrize def test_raw_response_list_price_adjustments(self, client: Metronome) -> None: response = client.customers.plans.with_raw_response.list_price_adjustments( - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", ) assert response.is_closed is True @@ -270,8 +244,8 @@ def test_raw_response_list_price_adjustments(self, client: Metronome) -> None: @parametrize def test_streaming_response_list_price_adjustments(self, client: Metronome) -> None: with client.customers.plans.with_streaming_response.list_price_adjustments( - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", 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" @@ -285,14 +259,14 @@ def test_streaming_response_list_price_adjustments(self, client: Metronome) -> N 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.customers.plans.with_raw_response.list_price_adjustments( - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", 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.customers.plans.with_raw_response.list_price_adjustments( - customer_plan_id="", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + customer_plan_id="", ) @@ -368,17 +342,7 @@ async def test_method_add_with_all_params(self, async_client: AsyncMetronome) -> "custom_credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "fiat_currency_credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "to_fiat_conversion_factor": 0, - }, - { - "custom_credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "fiat_currency_credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "to_fiat_conversion_factor": 0, - }, - { - "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=[ { @@ -388,23 +352,7 @@ async def test_method_add_with_all_params(self, async_client: AsyncMetronome) -> "quantity": 0, "tier": 0, "value": 0, - }, - { - "adjustment_type": "percentage", - "charge_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "start_period": 0, - "quantity": 0, - "tier": 0, - "value": 0, - }, - { - "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, @@ -456,16 +404,16 @@ async def test_path_params_add(self, async_client: AsyncMetronome) -> None: @parametrize async def test_method_end(self, async_client: AsyncMetronome) -> None: plan = await async_client.customers.plans.end( - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", 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.customers.plans.end( - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", 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, @@ -475,8 +423,8 @@ async def test_method_end_with_all_params(self, async_client: AsyncMetronome) -> @parametrize async def test_raw_response_end(self, async_client: AsyncMetronome) -> None: response = await async_client.customers.plans.with_raw_response.end( - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", ) assert response.is_closed is True @@ -487,8 +435,8 @@ async def test_raw_response_end(self, async_client: AsyncMetronome) -> None: @parametrize async def test_streaming_response_end(self, async_client: AsyncMetronome) -> None: async with async_client.customers.plans.with_streaming_response.end( - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", 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" @@ -502,29 +450,29 @@ async def test_streaming_response_end(self, async_client: AsyncMetronome) -> Non 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.customers.plans.with_raw_response.end( - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", 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.customers.plans.with_raw_response.end( - customer_plan_id="", 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.customers.plans.list_price_adjustments( - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", 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.customers.plans.list_price_adjustments( - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", limit=1, next_page="next_page", ) @@ -533,8 +481,8 @@ async def test_method_list_price_adjustments_with_all_params(self, async_client: @parametrize async def test_raw_response_list_price_adjustments(self, async_client: AsyncMetronome) -> None: response = await async_client.customers.plans.with_raw_response.list_price_adjustments( - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", ) assert response.is_closed is True @@ -545,8 +493,8 @@ async def test_raw_response_list_price_adjustments(self, async_client: AsyncMetr @parametrize async def test_streaming_response_list_price_adjustments(self, async_client: AsyncMetronome) -> None: async with async_client.customers.plans.with_streaming_response.list_price_adjustments( - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", 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" @@ -560,12 +508,12 @@ async def test_streaming_response_list_price_adjustments(self, async_client: Asy 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.customers.plans.with_raw_response.list_price_adjustments( - customer_plan_id="7aa11640-0703-4600-8eb9-293f535a6b74", 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.customers.plans.with_raw_response.list_price_adjustments( - customer_plan_id="", customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + customer_plan_id="", ) diff --git a/tests/api_resources/test_alerts.py b/tests/api_resources/test_alerts.py index 7ca934a3..edb81c06 100644 --- a/tests/api_resources/test_alerts.py +++ b/tests/api_resources/test_alerts.py @@ -40,17 +40,7 @@ def test_method_create_with_all_params(self, client: Metronome) -> None: "entity": "Contract", "key": "key", "value": "value", - }, - { - "entity": "Contract", - "key": "key", - "value": "value", - }, - { - "entity": "Contract", - "key": "key", - "value": "value", - }, + } ], customer_id="4db51251-61de-4bfe-b9ce-495e244f3491", evaluate_on_create=True, @@ -58,11 +48,7 @@ def test_method_create_with_all_params(self, client: Metronome) -> None: "key": "key", "value": "value", }, - invoice_types_filter=[ - "PLAN_ARREARS, SCHEDULED, USAGE, CORRECTION, CREDIT_PURCHASE, or SEAT_PURCHASE", - "PLAN_ARREARS, SCHEDULED, USAGE, CORRECTION, CREDIT_PURCHASE, or SEAT_PURCHASE", - "PLAN_ARREARS, SCHEDULED, USAGE, CORRECTION, CREDIT_PURCHASE, or SEAT_PURCHASE", - ], + invoice_types_filter=["PLAN_ARREARS, SCHEDULED, USAGE, CORRECTION, CREDIT_PURCHASE, or SEAT_PURCHASE"], plan_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", uniqueness_key="x", ) @@ -103,6 +89,14 @@ def test_method_archive(self, client: Metronome) -> None: ) assert_matches_type(AlertArchiveResponse, alert, path=["response"]) + @parametrize + def test_method_archive_with_all_params(self, client: Metronome) -> None: + alert = client.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.alerts.with_raw_response.archive( @@ -154,17 +148,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncMetronome) "entity": "Contract", "key": "key", "value": "value", - }, - { - "entity": "Contract", - "key": "key", - "value": "value", - }, - { - "entity": "Contract", - "key": "key", - "value": "value", - }, + } ], customer_id="4db51251-61de-4bfe-b9ce-495e244f3491", evaluate_on_create=True, @@ -172,11 +156,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncMetronome) "key": "key", "value": "value", }, - invoice_types_filter=[ - "PLAN_ARREARS, SCHEDULED, USAGE, CORRECTION, CREDIT_PURCHASE, or SEAT_PURCHASE", - "PLAN_ARREARS, SCHEDULED, USAGE, CORRECTION, CREDIT_PURCHASE, or SEAT_PURCHASE", - "PLAN_ARREARS, SCHEDULED, USAGE, CORRECTION, CREDIT_PURCHASE, or SEAT_PURCHASE", - ], + invoice_types_filter=["PLAN_ARREARS, SCHEDULED, USAGE, CORRECTION, CREDIT_PURCHASE, or SEAT_PURCHASE"], plan_id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", uniqueness_key="x", ) @@ -217,6 +197,14 @@ async def test_method_archive(self, async_client: AsyncMetronome) -> None: ) 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.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.alerts.with_raw_response.archive( diff --git a/tests/api_resources/test_billable_metrics.py b/tests/api_resources/test_billable_metrics.py index f0a52b22..ef1f3bec 100644 --- a/tests/api_resources/test_billable_metrics.py +++ b/tests/api_resources/test_billable_metrics.py @@ -26,7 +26,6 @@ class TestBillableMetrics: @parametrize def test_method_create(self, client: Metronome) -> None: billable_metric = client.billable_metrics.create( - aggregation_type="COUNT", name="CPU Hours", ) assert_matches_type(BillableMetricCreateResponse, billable_metric, path=["response"]) @@ -34,42 +33,42 @@ def test_method_create(self, client: Metronome) -> None: @parametrize def test_method_create_with_all_params(self, client: Metronome) -> None: billable_metric = client.billable_metrics.create( - aggregation_type="COUNT", name="CPU Hours", aggregation_key="cpu_hours", + aggregation_type="COUNT", custom_fields={"foo": "string"}, event_type_filter={ "in_values": ["cpu_usage"], - "not_in_values": ["string", "string", "string"], + "not_in_values": ["string"], }, group_keys=[["region"], ["machine_type"]], property_filters=[ { "name": "cpu_hours", "exists": True, - "in_values": ["string", "string", "string"], - "not_in_values": ["string", "string", "string"], + "in_values": ["string"], + "not_in_values": ["string"], }, { "name": "region", "exists": True, "in_values": ["EU", "NA"], - "not_in_values": ["string", "string", "string"], + "not_in_values": ["string"], }, { "name": "machine_type", "exists": True, "in_values": ["slow", "fast"], - "not_in_values": ["string", "string", "string"], + "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.billable_metrics.with_raw_response.create( - aggregation_type="COUNT", name="CPU Hours", ) @@ -81,7 +80,6 @@ def test_raw_response_create(self, client: Metronome) -> None: @parametrize def test_streaming_response_create(self, client: Metronome) -> None: with client.billable_metrics.with_streaming_response.create( - aggregation_type="COUNT", name="CPU Hours", ) as response: assert not response.is_closed @@ -95,14 +93,14 @@ def test_streaming_response_create(self, client: Metronome) -> None: @parametrize def test_method_retrieve(self, client: Metronome) -> None: billable_metric = client.billable_metrics.retrieve( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + 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.billable_metrics.with_raw_response.retrieve( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + billable_metric_id="13117714-3f05-48e5-a6e9-a66093f13b4d", ) assert response.is_closed is True @@ -113,7 +111,7 @@ def test_raw_response_retrieve(self, client: Metronome) -> None: @parametrize def test_streaming_response_retrieve(self, client: Metronome) -> None: with client.billable_metrics.with_streaming_response.retrieve( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + 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" @@ -127,7 +125,7 @@ def test_streaming_response_retrieve(self, client: Metronome) -> None: 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.billable_metrics.with_raw_response.retrieve( - "", + billable_metric_id="", ) @parametrize @@ -138,6 +136,7 @@ def test_method_list(self, client: Metronome) -> None: @parametrize def test_method_list_with_all_params(self, client: Metronome) -> None: billable_metric = client.billable_metrics.list( + include_archived=True, limit=1, next_page="next_page", ) @@ -201,7 +200,6 @@ class TestAsyncBillableMetrics: @parametrize async def test_method_create(self, async_client: AsyncMetronome) -> None: billable_metric = await async_client.billable_metrics.create( - aggregation_type="COUNT", name="CPU Hours", ) assert_matches_type(BillableMetricCreateResponse, billable_metric, path=["response"]) @@ -209,42 +207,42 @@ async def test_method_create(self, async_client: AsyncMetronome) -> None: @parametrize async def test_method_create_with_all_params(self, async_client: AsyncMetronome) -> None: billable_metric = await async_client.billable_metrics.create( - aggregation_type="COUNT", name="CPU Hours", aggregation_key="cpu_hours", + aggregation_type="COUNT", custom_fields={"foo": "string"}, event_type_filter={ "in_values": ["cpu_usage"], - "not_in_values": ["string", "string", "string"], + "not_in_values": ["string"], }, group_keys=[["region"], ["machine_type"]], property_filters=[ { "name": "cpu_hours", "exists": True, - "in_values": ["string", "string", "string"], - "not_in_values": ["string", "string", "string"], + "in_values": ["string"], + "not_in_values": ["string"], }, { "name": "region", "exists": True, "in_values": ["EU", "NA"], - "not_in_values": ["string", "string", "string"], + "not_in_values": ["string"], }, { "name": "machine_type", "exists": True, "in_values": ["slow", "fast"], - "not_in_values": ["string", "string", "string"], + "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.billable_metrics.with_raw_response.create( - aggregation_type="COUNT", name="CPU Hours", ) @@ -256,7 +254,6 @@ async def test_raw_response_create(self, async_client: AsyncMetronome) -> None: @parametrize async def test_streaming_response_create(self, async_client: AsyncMetronome) -> None: async with async_client.billable_metrics.with_streaming_response.create( - aggregation_type="COUNT", name="CPU Hours", ) as response: assert not response.is_closed @@ -270,14 +267,14 @@ async def test_streaming_response_create(self, async_client: AsyncMetronome) -> @parametrize async def test_method_retrieve(self, async_client: AsyncMetronome) -> None: billable_metric = await async_client.billable_metrics.retrieve( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + 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.billable_metrics.with_raw_response.retrieve( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + billable_metric_id="13117714-3f05-48e5-a6e9-a66093f13b4d", ) assert response.is_closed is True @@ -288,7 +285,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncMetronome) -> None @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncMetronome) -> None: async with async_client.billable_metrics.with_streaming_response.retrieve( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + 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" @@ -302,7 +299,7 @@ async def test_streaming_response_retrieve(self, async_client: AsyncMetronome) - 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.billable_metrics.with_raw_response.retrieve( - "", + billable_metric_id="", ) @parametrize @@ -313,6 +310,7 @@ async def test_method_list(self, async_client: AsyncMetronome) -> None: @parametrize async def test_method_list_with_all_params(self, async_client: AsyncMetronome) -> None: billable_metric = await async_client.billable_metrics.list( + include_archived=True, limit=1, next_page="next_page", ) diff --git a/tests/api_resources/test_contracts.py b/tests/api_resources/test_contracts.py index 87116135..704d210f 100644 --- a/tests/api_resources/test_contracts.py +++ b/tests/api_resources/test_contracts.py @@ -57,27 +57,13 @@ def test_method_create_with_all_params(self, client: Metronome) -> None: "amount": 0, "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "string"], + "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "applicable_product_tags": ["string"], "custom_fields": {"foo": "string"}, "description": "description", "invoice_schedule": { @@ -97,128 +83,45 @@ def test_method_create_with_all_params(self, client: Metronome) -> None: "amount": 0, "quantity": 0, "unit_price": 0, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", "priority": 0, + "rate_type": "COMMIT_RATE", "rollover_fraction": 0, - }, + "temporary_id": "temporary_id", + } + ], + credits=[ { - "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"), - }, - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "string"], + "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", - "invoice_schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", "priority": 0, - "rollover_fraction": 0, - }, + "rate_type": "COMMIT_RATE", + } + ], + custom_fields={"foo": "string"}, + discounts=[ { "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"), - }, - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "invoice_schedule": { + "schedule": { "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "recurring_schedule": { "amount_distribution": "DIVIDED", @@ -235,133 +138,98 @@ def test_method_create_with_all_params(self, client: Metronome) -> None: "amount": 0, "quantity": 0, "unit_price": 0, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - "priority": 0, - "rollover_fraction": 0, - }, + } ], - credits=[ + ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), + multiplier_override_prioritization="LOWEST_MULTIPLIER", + name="name", + net_payment_terms_days=0, + netsuite_sales_order_id="netsuite_sales_order_id", + overrides=[ { - "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"), - }, - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, + "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": [ + { + "commit_ids": ["string"], + "presentation_group_values": {"foo": "string"}, + "pricing_group_values": {"foo": "string"}, + "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + "product_tags": ["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": [ { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, + "price": 0, + "size": 0, + } ], - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", }, + "priority": 0, "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "applicable_product_ids": [ - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + "target": "COMMIT_RATE", + "tiers": [ + { + "multiplier": 0, + "size": 0, + } ], - "applicable_product_tags": ["string", "string", "string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "priority": 0, - }, + "type": "OVERWRITE", + } + ], + professional_services=[ { - "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"), - }, - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "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", - }, + "max_amount": 0, "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "applicable_product_ids": [ - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "string"], + "quantity": 0, + "unit_price": 0, "custom_fields": {"foo": "string"}, "description": "description", - "name": "x", "netsuite_sales_order_id": "netsuite_sales_order_id", - "priority": 0, - }, + } + ], + rate_card_alias="rate_card_alias", + rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + reseller_royalties=[ { - "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"), - }, - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "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", + "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", }, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "applicable_product_ids": [ - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "priority": 0, - }, + "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, + } ], - custom_fields={"foo": "string"}, - discounts=[ + salesforce_opportunity_id="salesforce_opportunity_id", + scheduled_charges=[ { "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "schedule": { @@ -381,64 +249,239 @@ def test_method_create_with_all_params(self, client: Metronome) -> None: "amount": 0, "quantity": 0, "unit_price": 0, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - }, - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, + } + ], + scheduled_charges_on_usage_invoices="ALL", + 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.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.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.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.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.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.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.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.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.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.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.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.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", + 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.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.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.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.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": [ { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), "amount": 0, - "quantity": 0, - "unit_price": 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", }, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - }, - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { + "amount": 0, + "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "applicable_product_tags": ["string"], + "custom_fields": {"foo": "string"}, + "description": "description", + "invoice_schedule": { "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "recurring_schedule": { "amount_distribution": "DIVIDED", @@ -455,188 +498,86 @@ def test_method_create_with_all_params(self, client: Metronome) -> None: "amount": 0, "quantity": 0, "unit_price": 0, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - }, + "priority": 0, + "rate_type": "COMMIT_RATE", + "rollover_fraction": 0, + "temporary_id": "temporary_id", + } ], - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - multiplier_override_prioritization="LOWEST_MULTIPLIER", - name="name", - net_payment_terms_days=0, - netsuite_sales_order_id="netsuite_sales_order_id", - overrides=[ + credits=[ { - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "applicable_product_tags": ["string", "string", "string"], - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "entitled": True, - "multiplier": 0, - "override_specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "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, - }, - { - "price": 0, - "size": 0, - }, + "access_schedule": { + "schedule_items": [ { - "price": 0, - "size": 0, - }, + "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", }, - "priority": 0, "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "tiers": [ - { - "multiplier": 0, - "size": 0, - }, - { - "multiplier": 0, - "size": 0, - }, - { - "multiplier": 0, - "size": 0, - }, - ], - "type": "OVERWRITE", - }, + "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "applicable_product_tags": ["string"], + "custom_fields": {"foo": "string"}, + "description": "description", + "name": "x", + "netsuite_sales_order_id": "netsuite_sales_order_id", + "priority": 0, + "rate_type": "COMMIT_RATE", + } + ], + custom_fields={"foo": "string"}, + discounts=[ { - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "applicable_product_tags": ["string", "string", "string"], - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "entitled": True, - "multiplier": 0, - "override_specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - ], - "overwrite_rate": { - "rate_type": "FLAT", + "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + "schedule": { "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "custom_rate": {"foo": "bar"}, - "is_prorated": True, - "price": 0, - "quantity": 0, - "tiers": [ - { - "price": 0, - "size": 0, - }, - { - "price": 0, - "size": 0, - }, + "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": [ { - "price": 0, - "size": 0, - }, + "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), + "amount": 0, + "quantity": 0, + "unit_price": 0, + } ], }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "tiers": [ - { - "multiplier": 0, - "size": 0, - }, - { - "multiplier": 0, - "size": 0, - }, - { - "multiplier": 0, - "size": 0, - }, - ], - "type": "OVERWRITE", - }, + "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", "string", "string"], + "applicable_product_tags": ["string"], "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), "entitled": True, + "is_commit_specific": True, "multiplier": 0, "override_specifiers": [ { + "commit_ids": ["string"], "presentation_group_values": {"foo": "string"}, "pricing_group_values": {"foo": "string"}, "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, + "product_tags": ["string"], + } ], "overwrite_rate": { "rate_type": "FLAT", @@ -649,35 +590,20 @@ def test_method_create_with_all_params(self, client: Metronome) -> None: { "price": 0, "size": 0, - }, - { - "price": 0, - "size": 0, - }, - { - "price": 0, - "size": 0, - }, + } ], }, "priority": 0, "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + "target": "COMMIT_RATE", "tiers": [ { "multiplier": 0, "size": 0, - }, - { - "multiplier": 0, - "size": 0, - }, - { - "multiplier": 0, - "size": 0, - }, + } ], "type": "OVERWRITE", - }, + } ], professional_services=[ { @@ -688,98 +614,28 @@ def test_method_create_with_all_params(self, client: Metronome) -> None: "custom_fields": {"foo": "string"}, "description": "description", "netsuite_sales_order_id": "netsuite_sales_order_id", - }, - { - "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", - }, - { - "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", 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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "string"], + "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, - }, - { "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "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, - }, - { - "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "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, - }, + "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), + } ], salesforce_opportunity_id="salesforce_opportunity_id", scheduled_charges=[ @@ -802,122 +658,21 @@ def test_method_create_with_all_params(self, client: Metronome) -> None: "amount": 0, "quantity": 0, "unit_price": 0, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - }, - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - }, - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - }, + } ], 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", "string", "string"], - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - usage_statement_schedule={ - "frequency": "MONTHLY", - "day": "FIRST_OF_MONTH", - "invoice_generation_starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, ) - assert_matches_type(ContractCreateResponse, contract, path=["response"]) + assert_matches_type(ContractAmendResponse, contract, path=["response"]) @parametrize - def test_raw_response_create(self, client: Metronome) -> None: - response = client.contracts.with_raw_response.create( + def test_raw_response_amend(self, client: Metronome) -> None: + response = client.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"), ) @@ -925,11 +680,12 @@ def test_raw_response_create(self, client: Metronome) -> None: 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"]) + assert_matches_type(ContractAmendResponse, contract, path=["response"]) @parametrize - def test_streaming_response_create(self, client: Metronome) -> None: - with client.contracts.with_streaming_response.create( + def test_streaming_response_amend(self, client: Metronome) -> None: + with client.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: @@ -937,166 +693,404 @@ def test_streaming_response_create(self, client: Metronome) -> None: assert response.http_request.headers.get("X-Stainless-Lang") == "python" contract = response.parse() - assert_matches_type(ContractCreateResponse, contract, path=["response"]) + assert_matches_type(ContractAmendResponse, contract, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - def test_method_retrieve(self, client: Metronome) -> None: - contract = client.contracts.retrieve( + def test_method_archive(self, client: Metronome) -> None: + contract = client.contracts.archive( contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", + void_invoices=True, ) - assert_matches_type(ContractRetrieveResponse, contract, path=["response"]) + assert_matches_type(ContractArchiveResponse, contract, path=["response"]) @parametrize - def test_method_retrieve_with_all_params(self, client: Metronome) -> None: - contract = client.contracts.retrieve( + def test_raw_response_archive(self, client: Metronome) -> None: + response = client.contracts.with_raw_response.archive( contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - include_ledgers=True, + void_invoices=True, ) - assert_matches_type(ContractRetrieveResponse, contract, path=["response"]) + + 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_raw_response_retrieve(self, client: Metronome) -> None: - response = client.contracts.with_raw_response.retrieve( + def test_streaming_response_archive(self, client: Metronome) -> None: + with client.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.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.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(ContractRetrieveResponse, contract, path=["response"]) + assert_matches_type(ContractCreateHistoricalInvoicesResponse, contract, path=["response"]) @parametrize - def test_streaming_response_retrieve(self, client: Metronome) -> None: - with client.contracts.with_streaming_response.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", + def test_streaming_response_create_historical_invoices(self, client: Metronome) -> None: + with client.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(ContractRetrieveResponse, contract, path=["response"]) + assert_matches_type(ContractCreateHistoricalInvoicesResponse, contract, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - def test_method_list(self, client: Metronome) -> None: - contract = client.contracts.list( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", + def test_method_list_balances(self, client: Metronome) -> None: + contract = client.contracts.list_balances( + customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", ) - assert_matches_type(ContractListResponse, contract, path=["response"]) + assert_matches_type(ContractListBalancesResponse, contract, path=["response"]) @parametrize - def test_method_list_with_all_params(self, client: Metronome) -> None: - contract = client.contracts.list( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", + def test_method_list_balances_with_all_params(self, client: Metronome) -> None: + contract = client.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"), include_archived=True, + include_balance=True, + include_contract_balances=True, include_ledgers=True, + next_page="next_page", starting_at=parse_datetime("2019-12-27T18:11:19.117Z"), ) - assert_matches_type(ContractListResponse, contract, path=["response"]) + assert_matches_type(ContractListBalancesResponse, contract, path=["response"]) @parametrize - def test_raw_response_list(self, client: Metronome) -> None: - response = client.contracts.with_raw_response.list( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", + def test_raw_response_list_balances(self, client: Metronome) -> None: + response = client.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(ContractListResponse, contract, path=["response"]) + assert_matches_type(ContractListBalancesResponse, contract, path=["response"]) @parametrize - def test_streaming_response_list(self, client: Metronome) -> None: - with client.contracts.with_streaming_response.list( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", + def test_streaming_response_list_balances(self, client: Metronome) -> None: + with client.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(ContractListResponse, contract, path=["response"]) + assert_matches_type(ContractListBalancesResponse, 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.contracts.add_manual_balance_entry( - id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - amount=-1000, + def test_method_retrieve_rate_schedule(self, client: Metronome) -> None: + contract = client.contracts.retrieve_rate_schedule( + contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - reason="Reason for entry", - segment_id="66368e29-3f97-4d15-a6e9-120897f0070a", ) - assert contract is None + assert_matches_type(ContractRetrieveRateScheduleResponse, contract, path=["response"]) @parametrize - def test_method_add_manual_balance_entry_with_all_params(self, client: Metronome) -> None: - contract = client.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", + def test_method_retrieve_rate_schedule_with_all_params(self, client: Metronome) -> None: + contract = client.contracts.retrieve_rate_schedule( contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - timestamp=parse_datetime("2019-12-27T18:11:19.117Z"), + customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", + limit=1, + next_page="next_page", + at=parse_datetime("2020-01-01T00:00:00.000Z"), + selectors=[ + { + "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 contract is None + assert_matches_type(ContractRetrieveRateScheduleResponse, contract, path=["response"]) @parametrize - def test_raw_response_add_manual_balance_entry(self, client: Metronome) -> None: - response = client.contracts.with_raw_response.add_manual_balance_entry( - id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - amount=-1000, + def test_raw_response_retrieve_rate_schedule(self, client: Metronome) -> None: + response = client.contracts.with_raw_response.retrieve_rate_schedule( + contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", 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 + assert_matches_type(ContractRetrieveRateScheduleResponse, contract, path=["response"]) @parametrize - def test_streaming_response_add_manual_balance_entry(self, client: Metronome) -> None: - with client.contracts.with_streaming_response.add_manual_balance_entry( - id="6162d87b-e5db-4a33-b7f2-76ce6ead4e85", - amount=-1000, + def test_streaming_response_retrieve_rate_schedule(self, client: Metronome) -> None: + with client.contracts.with_streaming_response.retrieve_rate_schedule( + contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", 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_matches_type(ContractRetrieveRateScheduleResponse, contract, path=["response"]) assert cast(Any, response.is_closed) is True @parametrize - def test_method_amend(self, client: Metronome) -> None: - contract = client.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"), + def test_method_schedule_pro_services_invoice(self, client: Metronome) -> None: + contract = client.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(ContractAmendResponse, contract, path=["response"]) + assert_matches_type(ContractScheduleProServicesInvoiceResponse, contract, path=["response"]) @parametrize - def test_method_amend_with_all_params(self, client: Metronome) -> None: - contract = client.contracts.amend( + def test_method_schedule_pro_services_invoice_with_all_params(self, client: Metronome) -> None: + contract = client.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.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.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.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.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.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.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.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.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.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], indirect=True, ids=["loose", "strict"]) + + @parametrize + async def test_method_create(self, async_client: AsyncMetronome) -> None: + contract = await async_client.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.contracts.create( + customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), + billing_provider_configuration={ + "billing_provider": "aws_marketplace", + "billing_provider_configuration_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + "delivery_method": "direct_to_billing_provider", + }, commits=[ { "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", @@ -1107,27 +1101,13 @@ def test_method_amend_with_all_params(self, client: Metronome) -> None: "amount": 0, "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "string"], + "applicable_product_ids": ["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], + "applicable_product_tags": ["string"], "custom_fields": {"foo": "string"}, "description": "description", "invoice_schedule": { @@ -1147,59 +1127,45 @@ def test_method_amend_with_all_params(self, client: Metronome) -> None: "amount": 0, "quantity": 0, "unit_price": 0, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", "priority": 0, + "rate_type": "COMMIT_RATE", "rollover_fraction": 0, - }, + "temporary_id": "temporary_id", + } + ], + credits=[ { - "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"), - }, - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "string"], + "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", - "invoice_schedule": { + "name": "x", + "netsuite_sales_order_id": "netsuite_sales_order_id", + "priority": 0, + "rate_type": "COMMIT_RATE", + } + ], + custom_fields={"foo": "string"}, + discounts=[ + { + "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + "schedule": { "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "recurring_schedule": { "amount_distribution": "DIVIDED", @@ -1216,276 +1182,98 @@ def test_method_amend_with_all_params(self, client: Metronome) -> None: "amount": 0, "quantity": 0, "unit_price": 0, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - "priority": 0, - "rollover_fraction": 0, - }, + } + ], + ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), + multiplier_override_prioritization="LOWEST_MULTIPLIER", + name="name", + net_payment_terms_days=0, + netsuite_sales_order_id="netsuite_sales_order_id", + overrides=[ { - "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"), - }, - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + "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": [ + { + "commit_ids": ["string"], + "presentation_group_values": {"foo": "string"}, + "pricing_group_values": {"foo": "string"}, + "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + "product_tags": ["string"], + } ], - "applicable_product_tags": ["string", "string", "string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "invoice_schedule": { + "overwrite_rate": { + "rate_type": "FLAT", "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - "priority": 0, - "rollover_fraction": 0, - }, - ], - 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"), - }, - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, + "custom_rate": {"foo": "bar"}, + "is_prorated": True, + "price": 0, + "quantity": 0, + "tiers": [ { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, + "price": 0, + "size": 0, + } ], - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", }, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "applicable_product_ids": [ - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", "priority": 0, - }, - { - "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"), - }, - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + "target": "COMMIT_RATE", + "tiers": [ + { + "multiplier": 0, + "size": 0, + } ], - "applicable_product_tags": ["string", "string", "string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "priority": 0, - }, + "type": "OVERWRITE", + } + ], + professional_services=[ { - "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"), - }, - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "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", - }, + "max_amount": 0, "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "applicable_product_ids": [ - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "string"], + "quantity": 0, + "unit_price": 0, "custom_fields": {"foo": "string"}, "description": "description", - "name": "x", "netsuite_sales_order_id": "netsuite_sales_order_id", - "priority": 0, - }, + } ], - custom_fields={"foo": "string"}, - discounts=[ + rate_card_alias="rate_card_alias", + rate_card_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + reseller_royalties=[ { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - ], + "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", }, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - }, - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - ], + "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), + "gcp_options": { + "gcp_account_id": "gcp_account_id", + "gcp_offer_id": "gcp_offer_id", }, - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - }, + "reseller_contract_value": 0, + } + ], + salesforce_opportunity_id="salesforce_opportunity_id", + scheduled_charges=[ { "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "schedule": { @@ -1505,2859 +1293,239 @@ def test_method_amend_with_all_params(self, client: Metronome) -> None: "amount": 0, "quantity": 0, "unit_price": 0, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - }, + } ], - netsuite_sales_order_id="netsuite_sales_order_id", - overrides=[ - { - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "applicable_product_tags": ["string", "string", "string"], - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "entitled": True, - "multiplier": 0, - "override_specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "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, - }, - { - "price": 0, - "size": 0, - }, - { - "price": 0, - "size": 0, - }, - ], - }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "tiers": [ - { - "multiplier": 0, - "size": 0, - }, - { - "multiplier": 0, - "size": 0, - }, - { - "multiplier": 0, - "size": 0, - }, - ], - "type": "OVERWRITE", - }, - { - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "applicable_product_tags": ["string", "string", "string"], - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "entitled": True, - "multiplier": 0, - "override_specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "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, - }, - { - "price": 0, - "size": 0, - }, - { - "price": 0, - "size": 0, - }, - ], - }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "tiers": [ - { - "multiplier": 0, - "size": 0, - }, - { - "multiplier": 0, - "size": 0, - }, - { - "multiplier": 0, - "size": 0, - }, - ], - "type": "OVERWRITE", - }, - { - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "applicable_product_tags": ["string", "string", "string"], - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "entitled": True, - "multiplier": 0, - "override_specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "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, - }, - { - "price": 0, - "size": 0, - }, - { - "price": 0, - "size": 0, - }, - ], - }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "tiers": [ - { - "multiplier": 0, - "size": 0, - }, - { - "multiplier": 0, - "size": 0, - }, - { - "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", - }, - { - "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", - }, - { - "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "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"), - }, - { - "reseller_type": "AWS", - "applicable_product_ids": [ - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "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"), - }, - { - "reseller_type": "AWS", - "applicable_product_ids": [ - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "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", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - }, - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - }, - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - }, - ], - total_contract_value=0, - ) - assert_matches_type(ContractAmendResponse, contract, path=["response"]) - - @parametrize - def test_raw_response_amend(self, client: Metronome) -> None: - response = client.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.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.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.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.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.contracts.create_historical_invoices( - invoices=[ - { - "contract_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "customer_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "issue_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "usage_line_items": [ - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - ], - }, - { - "contract_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "customer_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "issue_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "usage_line_items": [ - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - ], - }, - { - "contract_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "customer_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "issue_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "usage_line_items": [ - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - ], - }, - ], - preview=True, - ) - assert_matches_type(ContractCreateHistoricalInvoicesResponse, contract, path=["response"]) - - @parametrize - def test_raw_response_create_historical_invoices(self, client: Metronome) -> None: - response = client.contracts.with_raw_response.create_historical_invoices( - invoices=[ - { - "contract_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "customer_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "issue_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "usage_line_items": [ - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - ], - }, - { - "contract_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "customer_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "issue_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "usage_line_items": [ - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - ], - }, - { - "contract_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "customer_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "issue_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "usage_line_items": [ - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - ], - }, - ], - preview=True, - ) - - 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.contracts.with_streaming_response.create_historical_invoices( - invoices=[ - { - "contract_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "customer_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "issue_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "usage_line_items": [ - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - ], - }, - { - "contract_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "customer_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "issue_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "usage_line_items": [ - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - ], - }, - { - "contract_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "customer_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "issue_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "usage_line_items": [ - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - ], - }, - ], - preview=True, - ) 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_list_balances(self, client: Metronome) -> None: - contract = client.contracts.list_balances( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - ) - assert_matches_type(ContractListBalancesResponse, contract, path=["response"]) - - @parametrize - def test_method_list_balances_with_all_params(self, client: Metronome) -> None: - contract = client.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"), - include_archived=True, - include_contract_balances=True, - include_ledgers=True, - next_page="next_page", - starting_at=parse_datetime("2019-12-27T18:11:19.117Z"), - ) - assert_matches_type(ContractListBalancesResponse, contract, path=["response"]) - - @parametrize - def test_raw_response_list_balances(self, client: Metronome) -> None: - response = client.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(ContractListBalancesResponse, contract, path=["response"]) - - @parametrize - def test_streaming_response_list_balances(self, client: Metronome) -> None: - with client.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(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.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.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=[ - { - "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", "string", "string"], - } - ], - ) - assert_matches_type(ContractRetrieveRateScheduleResponse, contract, path=["response"]) - - @parametrize - def test_raw_response_retrieve_rate_schedule(self, client: Metronome) -> None: - response = client.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.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_schedule_pro_services_invoice(self, client: Metronome) -> None: - contract = client.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"}, - {"professional_service_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}, - {"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.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, - }, - { - "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, - }, - { - "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.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"}, - {"professional_service_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}, - {"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.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"}, - {"professional_service_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}, - {"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.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.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.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.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.contracts.update_end_date( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - 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.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.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], indirect=True, ids=["loose", "strict"]) - - @parametrize - async def test_method_create(self, async_client: AsyncMetronome) -> None: - contract = await async_client.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.contracts.create( - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - starting_at=parse_datetime("2020-01-01T00:00:00.000Z"), - billing_provider_configuration={ - "billing_provider": "aws_marketplace", - "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"), - }, - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "invoice_schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - "priority": 0, - "rollover_fraction": 0, - }, - { - "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"), - }, - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "invoice_schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - "priority": 0, - "rollover_fraction": 0, - }, - { - "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"), - }, - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "invoice_schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - "priority": 0, - "rollover_fraction": 0, - }, - ], - 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"), - }, - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "priority": 0, - }, - { - "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"), - }, - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "priority": 0, - }, - { - "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"), - }, - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "priority": 0, - }, - ], - custom_fields={"foo": "string"}, - discounts=[ - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - }, - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - }, - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - }, - ], - ending_before=parse_datetime("2019-12-27T18:11:19.117Z"), - 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", "string", "string"], - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "entitled": True, - "multiplier": 0, - "override_specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "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, - }, - { - "price": 0, - "size": 0, - }, - { - "price": 0, - "size": 0, - }, - ], - }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "tiers": [ - { - "multiplier": 0, - "size": 0, - }, - { - "multiplier": 0, - "size": 0, - }, - { - "multiplier": 0, - "size": 0, - }, - ], - "type": "OVERWRITE", - }, - { - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "applicable_product_tags": ["string", "string", "string"], - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "entitled": True, - "multiplier": 0, - "override_specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "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, - }, - { - "price": 0, - "size": 0, - }, - { - "price": 0, - "size": 0, - }, - ], - }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "tiers": [ - { - "multiplier": 0, - "size": 0, - }, - { - "multiplier": 0, - "size": 0, - }, - { - "multiplier": 0, - "size": 0, - }, - ], - "type": "OVERWRITE", - }, - { - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "applicable_product_tags": ["string", "string", "string"], - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "entitled": True, - "multiplier": 0, - "override_specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "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, - }, - { - "price": 0, - "size": 0, - }, - { - "price": 0, - "size": 0, - }, - ], - }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "tiers": [ - { - "multiplier": 0, - "size": 0, - }, - { - "multiplier": 0, - "size": 0, - }, - { - "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", - }, - { - "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", - }, - { - "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", - 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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "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, - }, - { - "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "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, - }, - { - "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "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, - }, - ], - salesforce_opportunity_id="salesforce_opportunity_id", - scheduled_charges=[ - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - }, - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - }, - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - }, - ], - 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", "string", "string"], - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - usage_statement_schedule={ - "frequency": "MONTHLY", - "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.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.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.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.contracts.retrieve( - contract_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", - customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", - 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.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.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.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.contracts.list( - customer_id="9b85c1c1-5238-4f2a-a409-61412905e1e1", - covering_date=parse_datetime("2019-12-27T18:11:19.117Z"), - include_archived=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.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.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.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.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", - 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.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.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.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.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"), - }, - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "invoice_schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - "priority": 0, - "rollover_fraction": 0, - }, - { - "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"), - }, - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "invoice_schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - "priority": 0, - "rollover_fraction": 0, - }, - { - "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"), - }, - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "invoice_schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - "priority": 0, - "rollover_fraction": 0, - }, - ], - 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"), - }, - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "priority": 0, - }, - { - "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"), - }, - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "priority": 0, - }, - { - "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"), - }, - { - "amount": 0, - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - }, - { - "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "string"], - "custom_fields": {"foo": "string"}, - "description": "description", - "name": "x", - "netsuite_sales_order_id": "netsuite_sales_order_id", - "priority": 0, - }, - ], - custom_fields={"foo": "string"}, - discounts=[ - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - }, - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - }, - { - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "schedule": { - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "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, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - }, - ], - netsuite_sales_order_id="netsuite_sales_order_id", - overrides=[ - { - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "applicable_product_tags": ["string", "string", "string"], - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "entitled": True, - "multiplier": 0, - "override_specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "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, - }, - { - "price": 0, - "size": 0, - }, - { - "price": 0, - "size": 0, - }, - ], - }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "tiers": [ - { - "multiplier": 0, - "size": 0, - }, - { - "multiplier": 0, - "size": 0, - }, - { - "multiplier": 0, - "size": 0, - }, - ], - "type": "OVERWRITE", - }, + scheduled_charges_on_usage_invoices="ALL", + 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.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.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.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.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.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.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.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.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.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.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.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.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", + 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.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.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.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.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=[ { - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "applicable_product_tags": ["string", "string", "string"], - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "entitled": True, - "multiplier": 0, - "override_specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "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, - }, - { - "price": 0, - "size": 0, - }, - { - "price": 0, - "size": 0, - }, - ], - }, - "priority": 0, "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "tiers": [ - { - "multiplier": 0, - "size": 0, - }, - { - "multiplier": 0, - "size": 0, - }, - { - "multiplier": 0, - "size": 0, - }, - ], - "type": "OVERWRITE", - }, - { - "starting_at": parse_datetime("2019-12-27T18:11:19.117Z"), - "applicable_product_tags": ["string", "string", "string"], - "ending_before": parse_datetime("2019-12-27T18:11:19.117Z"), - "entitled": True, - "multiplier": 0, - "override_specifiers": [ - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "string"], - }, - { - "presentation_group_values": {"foo": "string"}, - "pricing_group_values": {"foo": "string"}, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "product_tags": ["string", "string", "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, - }, - { - "price": 0, - "size": 0, - }, + "type": "PREPAID", + "access_schedule": { + "schedule_items": [ { - "price": 0, - "size": 0, - }, - ], - }, - "priority": 0, - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "tiers": [ - { - "multiplier": 0, - "size": 0, - }, - { - "multiplier": 0, - "size": 0, - }, - { - "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", - }, - { - "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", - }, - { - "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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "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"), - }, - { - "reseller_type": "AWS", - "applicable_product_ids": [ - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "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"), - }, - { - "reseller_type": "AWS", - "applicable_product_ids": [ - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], - "applicable_product_tags": ["string", "string", "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": { + "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", + "invoice_schedule": { "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "recurring_schedule": { "amount_distribution": "DIVIDED", @@ -4374,24 +1542,42 @@ async def test_method_amend_with_all_params(self, async_client: AsyncMetronome) "amount": 0, "quantity": 0, "unit_price": 0, - }, - { - "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", + "priority": 0, + "rate_type": "COMMIT_RATE", + "rollover_fraction": 0, + "temporary_id": "temporary_id", + } + ], + credits=[ + { + "access_schedule": { + "schedule_items": [ { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), "amount": 0, - "quantity": 0, - "unit_price": 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", "name": "x", "netsuite_sales_order_id": "netsuite_sales_order_id", - }, + "priority": 0, + "rate_type": "COMMIT_RATE", + } + ], + custom_fields={"foo": "string"}, + discounts=[ { "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", "schedule": { @@ -4411,24 +1597,92 @@ async def test_method_amend_with_all_params(self, async_client: AsyncMetronome) "amount": 0, "quantity": 0, "unit_price": 0, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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": [ + { + "commit_ids": ["string"], + "presentation_group_values": {"foo": "string"}, + "pricing_group_values": {"foo": "string"}, + "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + "product_tags": ["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": { @@ -4448,24 +1702,12 @@ async def test_method_amend_with_all_params(self, async_client: AsyncMetronome) "amount": 0, "quantity": 0, "unit_price": 0, - }, - { - "timestamp": parse_datetime("2019-12-27T18:11:19.117Z"), - "amount": 0, - "quantity": 0, - "unit_price": 0, - }, - { - "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", - }, + } ], total_contract_value=0, ) @@ -4541,82 +1783,22 @@ async def test_method_create_historical_invoices(self, async_client: AsyncMetron contract = await async_client.contracts.create_historical_invoices( invoices=[ { - "contract_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "customer_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "issue_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "usage_line_items": [ - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - ], - }, - { - "contract_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "customer_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "issue_date": parse_datetime("2019-12-27T18:11:19.117Z"), + "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("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - ], - }, - { - "contract_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "customer_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "issue_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "usage_line_items": [ - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, + "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=True, + preview=False, ) assert_matches_type(ContractCreateHistoricalInvoicesResponse, contract, path=["response"]) @@ -4625,82 +1807,22 @@ async def test_raw_response_create_historical_invoices(self, async_client: Async response = await async_client.contracts.with_raw_response.create_historical_invoices( invoices=[ { - "contract_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "customer_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "issue_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "usage_line_items": [ - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - ], - }, - { - "contract_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "customer_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "issue_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "usage_line_items": [ - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - ], - }, - { - "contract_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "customer_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "issue_date": parse_datetime("2019-12-27T18:11:19.117Z"), + "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("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, + "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=True, + preview=False, ) assert response.is_closed is True @@ -4713,82 +1835,22 @@ async def test_streaming_response_create_historical_invoices(self, async_client: async with async_client.contracts.with_streaming_response.create_historical_invoices( invoices=[ { - "contract_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "customer_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "issue_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "usage_line_items": [ - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - ], - }, - { - "contract_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "customer_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "issue_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "usage_line_items": [ - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - ], - }, - { - "contract_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "credit_type_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "customer_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "issue_date": parse_datetime("2019-12-27T18:11:19.117Z"), + "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("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, - { - "exclusive_end_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "inclusive_start_date": parse_datetime("2019-12-27T18:11:19.117Z"), - "product_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - }, + "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=True, + preview=False, ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -4813,6 +1875,7 @@ async def test_method_list_balances_with_all_params(self, async_client: AsyncMet 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_balances=True, include_ledgers=True, next_page="next_page", @@ -4868,7 +1931,7 @@ async def test_method_retrieve_rate_schedule_with_all_params(self, async_client: }, "pricing_group_values": {"foo": "string"}, "product_id": "d6300dbb-882e-4d2d-8dec-5125d16b65d0", - "product_tags": ["string", "string", "string"], + "product_tags": ["string"], } ], ) @@ -4906,11 +1969,7 @@ async def test_method_schedule_pro_services_invoice(self, async_client: AsyncMet 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"}, - {"professional_service_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}, - {"professional_service_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}, - ], + line_items=[{"professional_service_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], ) assert_matches_type(ContractScheduleProServicesInvoiceResponse, contract, path=["response"]) @@ -4930,27 +1989,7 @@ async def test_method_schedule_pro_services_invoice_with_all_params(self, async_ "netsuite_invoice_billing_start": parse_datetime("2019-12-27T18:11:19.117Z"), "quantity": 0, "unit_price": 0, - }, - { - "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, - }, - { - "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"), @@ -4963,11 +2002,7 @@ async def test_raw_response_schedule_pro_services_invoice(self, async_client: As 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"}, - {"professional_service_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}, - {"professional_service_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}, - ], + line_items=[{"professional_service_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}], ) assert response.is_closed is True @@ -4981,11 +2016,7 @@ async def test_streaming_response_schedule_pro_services_invoice(self, async_clie 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"}, - {"professional_service_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}, - {"professional_service_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"}, - ], + 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" @@ -5051,6 +2082,7 @@ async def test_method_update_end_date_with_all_params(self, async_client: AsyncM contract = await async_client.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"]) diff --git a/tests/api_resources/test_credit_grants.py b/tests/api_resources/test_credit_grants.py index 01ce16e1..ed885e56 100644 --- a/tests/api_resources/test_credit_grants.py +++ b/tests/api_resources/test_credit_grants.py @@ -63,11 +63,7 @@ def test_method_create_with_all_params(self, client: Metronome) -> None: 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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], + product_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], reason="Incentivize new customer", rollover_settings={ "expires_at": parse_datetime("2019-12-27T18:11:19.117Z"), @@ -137,11 +133,7 @@ def test_method_list_with_all_params(self, client: Metronome) -> None: credit_grant = client.credit_grants.list( limit=1, next_page="next_page", - credit_grant_ids=[ - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], + 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"), @@ -282,14 +274,14 @@ def test_streaming_response_list_entries(self, client: Metronome) -> None: @parametrize def test_method_void(self, client: Metronome) -> None: credit_grant = client.credit_grants.void( - id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + 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.credit_grants.void( - id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + id="9b85c1c1-5238-4f2a-a409-61412905e1e1", release_uniqueness_key=True, void_credit_purchase_invoice=True, ) @@ -298,7 +290,7 @@ def test_method_void_with_all_params(self, client: Metronome) -> None: @parametrize def test_raw_response_void(self, client: Metronome) -> None: response = client.credit_grants.with_raw_response.void( - id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + id="9b85c1c1-5238-4f2a-a409-61412905e1e1", ) assert response.is_closed is True @@ -309,7 +301,7 @@ def test_raw_response_void(self, client: Metronome) -> None: @parametrize def test_streaming_response_void(self, client: Metronome) -> None: with client.credit_grants.with_streaming_response.void( - id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + id="9b85c1c1-5238-4f2a-a409-61412905e1e1", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -360,11 +352,7 @@ async def test_method_create_with_all_params(self, async_client: AsyncMetronome) 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", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], + product_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], reason="Incentivize new customer", rollover_settings={ "expires_at": parse_datetime("2019-12-27T18:11:19.117Z"), @@ -434,11 +422,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncMetronome) - credit_grant = await async_client.credit_grants.list( limit=1, next_page="next_page", - credit_grant_ids=[ - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - ], + 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"), @@ -579,14 +563,14 @@ async def test_streaming_response_list_entries(self, async_client: AsyncMetronom @parametrize async def test_method_void(self, async_client: AsyncMetronome) -> None: credit_grant = await async_client.credit_grants.void( - id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + 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.credit_grants.void( - id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + id="9b85c1c1-5238-4f2a-a409-61412905e1e1", release_uniqueness_key=True, void_credit_purchase_invoice=True, ) @@ -595,7 +579,7 @@ async def test_method_void_with_all_params(self, async_client: AsyncMetronome) - @parametrize async def test_raw_response_void(self, async_client: AsyncMetronome) -> None: response = await async_client.credit_grants.with_raw_response.void( - id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + id="9b85c1c1-5238-4f2a-a409-61412905e1e1", ) assert response.is_closed is True @@ -606,7 +590,7 @@ async def test_raw_response_void(self, async_client: AsyncMetronome) -> None: @parametrize async def test_streaming_response_void(self, async_client: AsyncMetronome) -> None: async with async_client.credit_grants.with_streaming_response.void( - id="182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + id="9b85c1c1-5238-4f2a-a409-61412905e1e1", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" diff --git a/tests/api_resources/test_custom_fields.py b/tests/api_resources/test_custom_fields.py index 6a5941cd..4069e431 100644 --- a/tests/api_resources/test_custom_fields.py +++ b/tests/api_resources/test_custom_fields.py @@ -102,7 +102,7 @@ def test_method_list_keys(self, client: Metronome) -> None: def test_method_list_keys_with_all_params(self, client: Metronome) -> None: custom_field = client.custom_fields.list_keys( next_page="next_page", - entities=["alert", "billable_metric"], + entities=["alert"], ) assert_matches_type(CustomFieldListKeysResponse, custom_field, path=["response"]) @@ -284,7 +284,7 @@ async def test_method_list_keys(self, async_client: AsyncMetronome) -> None: async def test_method_list_keys_with_all_params(self, async_client: AsyncMetronome) -> None: custom_field = await async_client.custom_fields.list_keys( next_page="next_page", - entities=["alert", "billable_metric"], + entities=["alert"], ) assert_matches_type(CustomFieldListKeysResponse, custom_field, path=["response"]) diff --git a/tests/api_resources/test_customers.py b/tests/api_resources/test_customers.py index 557fa158..cab25123 100644 --- a/tests/api_resources/test_customers.py +++ b/tests/api_resources/test_customers.py @@ -41,11 +41,23 @@ def test_method_create_with_all_params(self, client: Metronome) -> None: billing_config={ "billing_provider_customer_id": "billing_provider_customer_id", "billing_provider_type": "aws_marketplace", + "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": "aws_marketplace", + "configuration": { + "stripe_customer_id": "bar", + "stripe_collection_method": "bar", + }, + "delivery_method": "direct_to_billing_provider", + "delivery_method_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + } + ], external_id="x", ingest_aliases=["team@example.com"], ) @@ -78,14 +90,14 @@ def test_streaming_response_create(self, client: Metronome) -> None: @parametrize def test_method_retrieve(self, client: Metronome) -> None: customer = client.customers.retrieve( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + 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.customers.with_raw_response.retrieve( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", ) assert response.is_closed is True @@ -96,7 +108,7 @@ def test_raw_response_retrieve(self, client: Metronome) -> None: @parametrize def test_streaming_response_retrieve(self, client: Metronome) -> None: with client.customers.with_streaming_response.retrieve( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -110,7 +122,7 @@ def test_streaming_response_retrieve(self, client: Metronome) -> None: 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.customers.with_raw_response.retrieve( - "", + customer_id="", ) @parametrize @@ -121,12 +133,12 @@ def test_method_list(self, client: Metronome) -> None: @parametrize def test_method_list_with_all_params(self, client: Metronome) -> None: customer = client.customers.list( - customer_ids=["string", "string", "string"], + customer_ids=["string"], ingest_alias="ingest_alias", limit=1, next_page="next_page", only_archived=True, - salesforce_account_ids=["string", "string", "string"], + salesforce_account_ids=["string"], ) assert_matches_type(SyncCursorPage[CustomerDetail], customer, path=["response"]) @@ -192,6 +204,7 @@ def test_method_list_billable_metrics(self, client: Metronome) -> None: def test_method_list_billable_metrics_with_all_params(self, client: Metronome) -> None: customer = client.customers.list_billable_metrics( customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + include_archived=True, limit=1, next_page="next_page", on_current_plan=True, @@ -435,11 +448,23 @@ async def test_method_create_with_all_params(self, async_client: AsyncMetronome) billing_config={ "billing_provider_customer_id": "billing_provider_customer_id", "billing_provider_type": "aws_marketplace", + "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": "aws_marketplace", + "configuration": { + "stripe_customer_id": "bar", + "stripe_collection_method": "bar", + }, + "delivery_method": "direct_to_billing_provider", + "delivery_method_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + } + ], external_id="x", ingest_aliases=["team@example.com"], ) @@ -472,14 +497,14 @@ async def test_streaming_response_create(self, async_client: AsyncMetronome) -> @parametrize async def test_method_retrieve(self, async_client: AsyncMetronome) -> None: customer = await async_client.customers.retrieve( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + 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.customers.with_raw_response.retrieve( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", ) assert response.is_closed is True @@ -490,7 +515,7 @@ async def test_raw_response_retrieve(self, async_client: AsyncMetronome) -> None @parametrize async def test_streaming_response_retrieve(self, async_client: AsyncMetronome) -> None: async with async_client.customers.with_streaming_response.retrieve( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -504,7 +529,7 @@ async def test_streaming_response_retrieve(self, async_client: AsyncMetronome) - 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.customers.with_raw_response.retrieve( - "", + customer_id="", ) @parametrize @@ -515,12 +540,12 @@ async def test_method_list(self, async_client: AsyncMetronome) -> None: @parametrize async def test_method_list_with_all_params(self, async_client: AsyncMetronome) -> None: customer = await async_client.customers.list( - customer_ids=["string", "string", "string"], + customer_ids=["string"], ingest_alias="ingest_alias", limit=1, next_page="next_page", only_archived=True, - salesforce_account_ids=["string", "string", "string"], + salesforce_account_ids=["string"], ) assert_matches_type(AsyncCursorPage[CustomerDetail], customer, path=["response"]) @@ -586,6 +611,7 @@ async def test_method_list_billable_metrics(self, async_client: AsyncMetronome) async def test_method_list_billable_metrics_with_all_params(self, async_client: AsyncMetronome) -> None: customer = await async_client.customers.list_billable_metrics( customer_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", + include_archived=True, limit=1, next_page="next_page", on_current_plan=True, diff --git a/tests/api_resources/test_dashboards.py b/tests/api_resources/test_dashboards.py index e62e48d4..1b8a8532 100644 --- a/tests/api_resources/test_dashboards.py +++ b/tests/api_resources/test_dashboards.py @@ -48,16 +48,12 @@ def test_method_get_embeddable_url_with_all_params(self, client: Metronome) -> N ], dashboard_options=[ { - "key": "key", - "value": "value", + "key": "show_zero_usage_line_items", + "value": "false", }, { - "key": "key", - "value": "value", - }, - { - "key": "key", - "value": "value", + "key": "hide_voided_invoices", + "value": "true", }, ], ) @@ -124,16 +120,12 @@ async def test_method_get_embeddable_url_with_all_params(self, async_client: Asy ], dashboard_options=[ { - "key": "key", - "value": "value", - }, - { - "key": "key", - "value": "value", + "key": "show_zero_usage_line_items", + "value": "false", }, { - "key": "key", - "value": "value", + "key": "hide_voided_invoices", + "value": "true", }, ], ) diff --git a/tests/api_resources/test_plans.py b/tests/api_resources/test_plans.py index eff29c16..5e65f7b8 100644 --- a/tests/api_resources/test_plans.py +++ b/tests/api_resources/test_plans.py @@ -59,14 +59,14 @@ def test_streaming_response_list(self, client: Metronome) -> None: @parametrize def test_method_get_details(self, client: Metronome) -> None: plan = client.plans.get_details( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + 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.plans.with_raw_response.get_details( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", ) assert response.is_closed is True @@ -77,7 +77,7 @@ def test_raw_response_get_details(self, client: Metronome) -> None: @parametrize def test_streaming_response_get_details(self, client: Metronome) -> None: with client.plans.with_streaming_response.get_details( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -91,7 +91,7 @@ def test_streaming_response_get_details(self, client: Metronome) -> None: 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.plans.with_raw_response.get_details( - "", + plan_id="", ) @parametrize @@ -229,14 +229,14 @@ async def test_streaming_response_list(self, async_client: AsyncMetronome) -> No @parametrize async def test_method_get_details(self, async_client: AsyncMetronome) -> None: plan = await async_client.plans.get_details( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + 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.plans.with_raw_response.get_details( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", ) assert response.is_closed is True @@ -247,7 +247,7 @@ async def test_raw_response_get_details(self, async_client: AsyncMetronome) -> N @parametrize async def test_streaming_response_get_details(self, async_client: AsyncMetronome) -> None: async with async_client.plans.with_streaming_response.get_details( - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + plan_id="d7abd0cd-4ae9-4db7-8676-e986a4ebd8dc", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -261,7 +261,7 @@ async def test_streaming_response_get_details(self, async_client: AsyncMetronome 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.plans.with_raw_response.get_details( - "", + plan_id="", ) @parametrize diff --git a/tests/api_resources/test_usage.py b/tests/api_resources/test_usage.py index b00011c7..826ed57b 100644 --- a/tests/api_resources/test_usage.py +++ b/tests/api_resources/test_usage.py @@ -45,27 +45,9 @@ def test_method_list_with_all_params(self, client: Metronome) -> None: "key": "key", "values": ["x"], }, - }, - { - "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "group_by": { - "key": "key", - "values": ["x"], - }, - }, - { - "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "group_by": { - "key": "key", - "values": ["x"], - }, - }, - ], - customer_ids=[ - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + } ], + customer_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], ) assert_matches_type(UsageListResponse, usage, path=["response"]) @@ -231,27 +213,9 @@ async def test_method_list_with_all_params(self, async_client: AsyncMetronome) - "key": "key", "values": ["x"], }, - }, - { - "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "group_by": { - "key": "key", - "values": ["x"], - }, - }, - { - "id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "group_by": { - "key": "key", - "values": ["x"], - }, - }, - ], - customer_ids=[ - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", - "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e", + } ], + customer_ids=["182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e"], ) assert_matches_type(UsageListResponse, usage, path=["response"]) diff --git a/tests/conftest.py b/tests/conftest.py index 0eebbfe8..28ca1ae0 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,11 +1,11 @@ from __future__ import annotations import os -import asyncio import logging from typing import TYPE_CHECKING, Iterator, AsyncIterator import pytest +from pytest_asyncio import is_async_test from metronome import Metronome, AsyncMetronome @@ -17,11 +17,13 @@ logging.getLogger("metronome").setLevel(logging.DEBUG) -@pytest.fixture(scope="session") -def event_loop() -> Iterator[asyncio.AbstractEventLoop]: - loop = asyncio.new_event_loop() - yield loop - loop.close() +# 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) base_url = os.environ.get("TEST_API_BASE_URL", "http://127.0.0.1:4010") diff --git a/tests/test_client.py b/tests/test_client.py index 4d387cbc..7db25630 100644 --- a/tests/test_client.py +++ b/tests/test_client.py @@ -4,12 +4,17 @@ import gc import os +import sys import json +import time import asyncio import inspect +import subprocess import tracemalloc from typing import Any, Union, cast +from textwrap import dedent from unittest import mock +from typing_extensions import Literal import httpx import pytest @@ -360,11 +365,11 @@ def test_default_query_option(self) -> None: FinalRequestOptions( method="get", url="/foo", - params={"foo": "baz", "query_param": "overriden"}, + params={"foo": "baz", "query_param": "overridden"}, ) ) url = httpx.URL(request.url) - assert dict(url.params) == {"foo": "baz", "query_param": "overriden"} + assert dict(url.params) == {"foo": "baz", "query_param": "overridden"} def test_request_extra_json(self) -> None: request = self.client._build_request( @@ -720,6 +725,7 @@ class Model(BaseModel): [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)) @@ -776,7 +782,14 @@ def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) -> Non @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_retries_taken(self, client: Metronome, failures_before_success: int, respx_mock: MockRouter) -> None: + @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 @@ -785,6 +798,8 @@ 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) @@ -797,6 +812,60 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: 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("/contracts/create").mock(side_effect=retry_handler) + + response = client.contracts.with_raw_response.create( + customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", + starting_at="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("/contracts/create").mock(side_effect=retry_handler) + + response = client.contracts.with_raw_response.create( + customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", + starting_at="2020-01-01T00:00:00.000Z", + extra_headers={"x-stainless-retry-count": "42"}, + ) + + assert response.http_request.headers.get("x-stainless-retry-count") == "42" + class TestAsyncMetronome: client = AsyncMetronome(base_url=base_url, bearer_token=bearer_token, _strict_response_validation=True) @@ -1108,11 +1177,11 @@ def test_default_query_option(self) -> None: FinalRequestOptions( method="get", url="/foo", - params={"foo": "baz", "query_param": "overriden"}, + params={"foo": "baz", "query_param": "overridden"}, ) ) url = httpx.URL(request.url) - assert dict(url.params) == {"foo": "baz", "query_param": "overriden"} + assert dict(url.params) == {"foo": "baz", "query_param": "overridden"} def test_request_extra_json(self) -> None: request = self.client._build_request( @@ -1471,6 +1540,7 @@ class Model(BaseModel): [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)) @@ -1529,8 +1599,13 @@ async def test_retrying_status_errors_doesnt_leak(self, respx_mock: MockRouter) @mock.patch("metronome._base_client.BaseClient._calculate_retry_timeout", _low_retry_timeout) @pytest.mark.respx(base_url=base_url) @pytest.mark.asyncio + @pytest.mark.parametrize("failure_mode", ["status", "exception"]) async def test_retries_taken( - self, async_client: AsyncMetronome, failures_before_success: int, respx_mock: MockRouter + 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) @@ -1540,6 +1615,8 @@ 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) @@ -1551,3 +1628,104 @@ def retry_handler(_request: httpx.Request) -> httpx.Response: 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) + @pytest.mark.asyncio + 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("/contracts/create").mock(side_effect=retry_handler) + + response = await client.contracts.with_raw_response.create( + customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", + starting_at="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) + @pytest.mark.asyncio + 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("/contracts/create").mock(side_effect=retry_handler) + + response = await client.contracts.with_raw_response.create( + customer_id="13117714-3f05-48e5-a6e9-a66093f13b4d", + starting_at="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_get_platform(self) -> None: + # A previous implementation of asyncify could leave threads unterminated when + # used with nest_asyncio. + # + # Since nest_asyncio.apply() is global and cannot be un-applied, this + # test is run in a separate process to avoid affecting other tests. + test_code = dedent(""" + import asyncio + import nest_asyncio + import threading + + from metronome._utils import asyncify + from metronome._base_client import get_platform + + async def test_main() -> None: + result = await asyncify(get_platform)() + print(result) + for thread in threading.enumerate(): + print(thread.name) + + nest_asyncio.apply() + asyncio.run(test_main()) + """) + with subprocess.Popen( + [sys.executable, "-c", test_code], + text=True, + ) as process: + timeout = 10 # seconds + + start_time = time.monotonic() + while True: + return_code = process.poll() + if return_code is not None: + if return_code != 0: + raise AssertionError("calling get_platform using asyncify resulted in a non-zero exit code") + + # success + break + + if time.monotonic() - start_time > timeout: + process.kill() + raise AssertionError("calling get_platform using asyncify resulted in a hung process") + + time.sleep(0.1) diff --git a/tests/test_models.py b/tests/test_models.py index 115f23e1..1ae9806f 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -1,7 +1,7 @@ import json from typing import Any, Dict, List, Union, Optional, cast from datetime import datetime, timezone -from typing_extensions import Literal, Annotated +from typing_extensions import Literal, Annotated, TypeAliasType import pytest import pydantic @@ -245,7 +245,7 @@ class Model(BaseModel): assert m.foo is True m = Model.construct(foo="CARD_HOLDER") - assert m.foo is "CARD_HOLDER" + assert m.foo == "CARD_HOLDER" m = Model.construct(foo={"bar": False}) assert isinstance(m.foo, Submodel1) @@ -520,19 +520,15 @@ class Model(BaseModel): assert m3.to_dict(exclude_none=True) == {} assert m3.to_dict(exclude_defaults=True) == {} - if PYDANTIC_V2: - - class Model2(BaseModel): - created_at: datetime + 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} - else: - with pytest.raises(ValueError, match="mode is only supported in Pydantic v2"): - m.to_dict(mode="json") + 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 not PYDANTIC_V2: with pytest.raises(ValueError, match="warnings is only supported in Pydantic v2"): m.to_dict(warnings=False) @@ -558,9 +554,6 @@ class Model(BaseModel): assert m3.model_dump(exclude_none=True) == {} if not PYDANTIC_V2: - with pytest.raises(ValueError, match="mode is only supported in Pydantic v2"): - m.model_dump(mode="json") - with pytest.raises(ValueError, match="round_trip is only supported in Pydantic v2"): m.model_dump(round_trip=True) @@ -568,6 +561,14 @@ class Model(BaseModel): 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) @@ -827,3 +828,29 @@ class B(BaseModel): # if the discriminator details object stays the same between invocations then # we hit the cache assert UnionType.__discriminator__ is discriminator + + +@pytest.mark.skipif(not PYDANTIC_V2, reason="TypeAliasType is not supported in Pydantic v1") +def test_type_alias_type() -> None: + Alias = TypeAliasType("Alias", str) + + 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(not PYDANTIC_V2, 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) diff --git a/tests/test_response.py b/tests/test_response.py index a13a2a0a..64eb64ad 100644 --- a/tests/test_response.py +++ b/tests/test_response.py @@ -190,6 +190,56 @@ async def test_async_response_parse_annotated_type(async_client: AsyncMetronome) 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 diff --git a/tests/test_transform.py b/tests/test_transform.py index 6a9c0aab..993b9092 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -177,17 +177,32 @@ 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") + tz = "Z" if PYDANTIC_V2 else "+00:00" assert await transform({"foo": dt}, DatetimeDict, use_async) == {"foo": "2023-02-23T14:16:36.337692+00:00"} # type: ignore[comparison-overlap] + assert await transform(DatetimeModel(foo=dt), Any, use_async) == {"foo": "2023-02-23T14:16:36.337692" + tz} # type: ignore[comparison-overlap] dt = dt.replace(tzinfo=None) assert await transform({"foo": dt}, DatetimeDict, use_async) == {"foo": "2023-02-23T14:16:36.337692"} # 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 diff --git a/tests/utils.py b/tests/utils.py index ff51aea1..d146e05c 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -16,6 +16,7 @@ is_union_type, extract_type_arg, is_annotated_type, + is_type_alias_type, ) from metronome._compat import PYDANTIC_V2, field_outer_type, get_model_fields from metronome._models import BaseModel @@ -51,6 +52,9 @@ def assert_matches_type( 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)